ajout de la page a propos

This commit is contained in:
Mathis 2025-04-02 23:35:20 +02:00
parent 07af6af1d4
commit ffa19ba1ba
18 changed files with 302 additions and 36 deletions

View File

@ -76,7 +76,9 @@ public class QueryObjects {
.put("type", row.getString("type"))
.put("location", row.getString("location"))
.put("last_update", row.getLocalDateTime("last_update").format(formatter))
.put("status", row.getString("status"));
.put("status", row.getString("status"))
.put("batterie",row.getInteger("batterie"))
.put("type_batterie",row.getString("type_batterie"));
objects.add(object);
}
return objects;

View File

@ -13,6 +13,7 @@
"lucide-react": "^0.427.0",
"react": "^18.3.1",
"react-charts": "^3.0.0-beta.57",
"react-circle-progress-bar": "^0.1.4",
"react-dom": "^18.3.1",
"react-router-dom": "^7.4.0",
"recharts": "^2.15.1"
@ -3584,6 +3585,55 @@
"react-dom": ">=16"
}
},
"node_modules/react-circle-progress-bar": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/react-circle-progress-bar/-/react-circle-progress-bar-0.1.4.tgz",
"integrity": "sha512-2a47TDthNyUHJf8p1hv0wcTwIWnJBbEUfj/7dZcO+7BYd1W1sRC2t5x+SEWX9/1QT7hhf4t8ppcLaG0XrdwwgQ==",
"license": "MIT",
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
},
"node_modules/react-circle-progress-bar/node_modules/react": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-circle-progress-bar/node_modules/react-dom": {
"version": "16.14.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.19.1"
},
"peerDependencies": {
"react": "^16.14.0"
}
},
"node_modules/react-circle-progress-bar/node_modules/scheduler": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",

View File

@ -14,6 +14,7 @@
"lucide-react": "^0.427.0",
"react": "^18.3.1",
"react-charts": "^3.0.0-beta.57",
"react-circle-progress-bar": "^0.1.4",
"react-dom": "^18.3.1",
"react-router-dom": "^7.4.0",
"recharts": "^2.15.1"

View File

@ -0,0 +1,27 @@
import React from "react";
import { Battery } from "lucide-react";
import Progress from "react-circle-progress-bar";
function BatterieInfo({ object }) {
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">
<Battery className="text-indigo-600" size={24} />
</div>
<h1 className="text-black text-2xl font-bold mb-1 ">
Etat de la batterie
</h1>
</div>
<div className="flex flex-col items-center">
<Progress progress={object.batterie} />
<h1 className="font-bold">
Type de batterie :{" "}
<span className="capitalize font-normal">{object.type_batterie}</span>
</h1>
</div>
</div>
);
}
export default BatterieInfo;

View File

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

View File

@ -14,10 +14,12 @@ function MeteoInfos({
AffPressionGraph,
defAffHumiditeGraph,
AffHumiditeGraph,
graphCible
}) {
const [rawData, setRawData] = useState([]);
const [AffAlert,setAffAlert] = useState(false);
const identifiant = object.id;
useEffect(() => {
axios.get(`${API_BASE_URL}/meteo?id=${identifiant}`).then((response) => {
setRawData(response.data);
@ -61,6 +63,8 @@ function MeteoInfos({
<BoutonGraphique
TypeAff={AffTempGraph}
setAffichage={defAffTempGraph}
graphCible={graphCible}
/>
</div>
</div>
@ -84,6 +88,7 @@ function MeteoInfos({
<BoutonGraphique
TypeAff={AffPressionGraph}
setAffichage={defAffPressionGraph}
graphCible={graphCible}
/>
</div>
</div>

View File

@ -70,7 +70,10 @@ function ModifObject({ object, defafficherModif }) {
</div>
<div className="mb-5">
<label htmlFor="type" className="block mb-2 text-sm font-medium text-gray-900">
<label
htmlFor="type"
className="block mb-2 text-sm font-medium text-gray-900"
>
Type :
</label>
<input
@ -84,7 +87,10 @@ function ModifObject({ object, defafficherModif }) {
</div>
<div className="mb-5">
<label htmlFor="location" className="block mb-2 text-sm font-medium text-gray-900">
<label
htmlFor="location"
className="block mb-2 text-sm font-medium text-gray-900"
>
Localisation :
</label>
<input
@ -98,7 +104,9 @@ function ModifObject({ object, defafficherModif }) {
</div>
<div className="mb-5">
<label className="block mb-2 text-sm font-medium text-gray-900">Status :</label>
<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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,11 +1,168 @@
import React from 'react';
import React from "react";
function About() {
return (
<div>
<h1>A propos</h1>
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="mb-5">
{/* Grille principale */}
<div className="grid md:grid-cols-2 gap-10 lg:gap-20 mb-5">
{/* Section Notre mission */}
<div className="order-1 md:order-1">
<h1 className="text-2xl font-bold text-gray-900 mb-6">
Notre mission
</h1>
<p className="text-gray-700 leading-relaxed">
Notre mission est de fournir une solution complète et innovante
pour la surveillance climatique et environnementale du
territoire français. En combinant des prévisions météorologiques
de haute qualité avec une gestion efficace des objets connectés,
nous visons à offrir une plateforme centralisée permettant de
surveiller en temps réel les conditions météorologiques locales,
tout en facilitant l'analyse des données collectées par des
objets connectés déployés à travers le pays.
</p>
</div>
<img
className="rounded-lg h-64 w-full object-cover order-2 md:order-2"
src="./src/img/NotreMission.png"
alt="Notre mission"
/>
{/* Section Qui sommes-nous */}
<img
className="rounded-lg h-64 w-full object-cover order-4 md:order-3"
src="./src/img/iotmeteo.jpg"
alt="IoT et météo"
/>
<div className="order-3 md:order-4">
<h1 className="text-2xl font-bold text-gray-900 mb-6">
Qui sommes-nous ?
</h1>
<p className="text-gray-700 leading-relaxed">
Nous sommes une équipe de passionnés de technologie,
dinnovation et denvironnement. Nous croyons fermement que la
combinaison de la donnée météorologique en temps réel et de
lInternet des Objets (IoT) peut avoir un impact majeur sur la
gestion des territoires. Que ce soit pour les collectivités
locales, les entreprises ou les acteurs publics, notre
plateforme offre les outils nécessaires pour une gestion
proactive et réactive de lenvironnement.
</p>
</div>
{/* Section Notre Vision */}
<div className="order-5 md:order-5">
<h1 className="text-2xl font-bold text-gray-900 mb-6">
Notre Vision
</h1>
<p className="text-gray-700 leading-relaxed">
Dans un monde les conditions climatiques évoluent rapidement,
il est essentiel de pouvoir anticiper et réagir efficacement
face aux phénomènes météorologiques. Grâce à nos objets
connectés et à notre interface intuitive, nous permettons aux
utilisateurs de suivre les conditions en temps réel et dagir en
conséquence. De la gestion des risques climatiques à la
planification urbaine, notre plateforme aide les décideurs à
prendre des décisions éclairées basées sur des données fiables
et locales.
</p>
</div>
<img
className="rounded-lg h-64 w-full object-cover order-6 md:order-6"
src="./src/img/surveillancemeteo.webp"
alt="Surveillance météo"
/>
</div>
{/* Section Objectifs */}
<div className="text-center col-span-2 order-7">
<h1 className="text-2xl font-bold text-gray-900 mb-10 mt-20">
Les Objectifs de Notre Plateforme
</h1>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-10">
{/* Objectif 1 */}
<div className="relative group w-full h-80 mb-7">
<img
src="./src/img/surveillancetempsreel.jpg"
alt="Surveillance en temps réel"
className="w-full h-full object-cover rounded-xl"
/>
<div className="absolute inset-0 bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity duration-500 rounded-xl flex items-center justify-center">
<p className="text-white text-lg font-bold px-4">
Grâce à nos objets connectés, nous collectons des données
météorologiques locales, permettant une surveillance
continue des conditions climatiques sur tout le territoire
français.
</p>
</div>
<h1 className="text-xl font-bold mt-4 ">
Surveillance en temps réel
</h1>
</div>
{/* Objectif 2 */}
<div className="relative group w-full h-80 mb-7">
<img
src="./src/img/precisionfiable.jpg"
alt="Précision fiable"
className="w-full h-full object-cover rounded-xl"
/>
<div className="absolute inset-0 bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity duration-500 rounded-xl flex items-center justify-center">
<p className="text-white text-lg font-bold px-4">
En utilisant les meilleures technologies de prévision
météorologique, nous vous fournissons des prévisions
précises, quil sagisse de la température, de la vitesse du
vent ou de la qualité de lair.
</p>
</div>
<h1 className="text-xl font-bold mt-4 mb-6">Prédiction fiable</h1>
</div>
{/* Objectif 3 */}
<div className="relative group w-full h-80 mb-7 border-2 rounded-xl">
<img
src="./src/img/gestioniot.png"
alt="Gestion IoT"
className="w-full h-full object-cover rounded-xl"
/>
<div className="absolute inset-0 bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity duration-500 rounded-xl flex items-center justify-center">
<p className="text-white text-lg font-bold px-4">
Nous permettons aux utilisateurs de gérer facilement leurs
objets connectés (stations météo, capteurs, etc.) à travers
une interface simple, tout en offrant un suivi en temps réel
de leur statut et de leurs données.
</p>
</div>
<h1 className="text-xl font-bold mt-4 mb-6">
Gestion des objets connectés
</h1>
</div>
{/* Objectif 4 */}
<div className="relative group w-full h-80 mb-7">
<img
src="./src/img/fr-alert.webp"
alt="Réponse rapide"
className="w-full h-full object-cover rounded-xl"
/>
<div className="absolute inset-0 bg-blue-600 opacity-0 group-hover:opacity-100 transition-opacity duration-500 rounded-xl flex items-center justify-center">
<p className="text-white text-lg font-bold px-4">
Notre plateforme vous envoie des alertes instantanées
concernant les phénomènes météorologiques extrêmes, vous
permettant de prendre des décisions rapides et adaptées.
</p>
</div>
<h1 className="text-xl font-bold mt-4 mb-6">
Réponse rapide aux alertes climatiques
</h1>
</div>
</div>
</div>
</div>
);
</div>
</div>
);
}
export default About;
export default About;

View File

@ -12,7 +12,6 @@ import {
Settings,
BadgePlus,
} from "lucide-react";
function Gestion() {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50">
@ -61,7 +60,6 @@ function Gestion() {
Ajouter un objet <ArrowRight size={16} className="ml-2" />
</a>
</div>
</div>
</div>
</div>

View File

@ -1,7 +1,7 @@
import React from "react";
import { Thermometer, CircleGauge, Droplet } from "lucide-react";
import { useEffect, useState } from "react";
import { useEffect, useState, useRef} from "react";
import axios from "axios";
import { API_BASE_URL } from "../../config";
@ -11,23 +11,32 @@ import WindGraph from "../../components/WindGraph";
import WindInfo from "../../components/WindInfo";
import MeteoInfos from "../../components/MeteoInfos";
import MeteoGraph from "../../components/MeteoGraph";
import BatterieInfo from "../../components/BatterieInfo";
function Objet() {
const identifiant = new URLSearchParams(window.location.search).get("id");
const [searchQuery, setSearchQuery] = useState("");
const [activeFilter, setActiveFilter] = useState("all");
const [object, setObject] = useState({});
const [graphStates, setGraphStates] = useState({
wind:false,
temperature:false,
pressure:false,
humidity:false,
})
const [afficherModif, defafficherModif] = useState(false);
const [AffWindGraph, defAffWindGraph] = useState(false);
const [AffTempGraph, defAffTempGraph] = useState(false);
const [AffPressionGraph, defAffPressionGraph] = useState(false);
const [AffHumiditeGraph, defAffHumideGraph] = useState(false);
const tempGraphRef = useRef(null);
const pressureGraphRef = useRef(null);
const humidityGraphRef = useRef(null);
const windGraphRef = useRef(null);
useEffect(() => {
axios
.get(`${API_BASE_URL}/objet?id=${identifiant}`)
.then((response) => {
setObject(response.data[0]);
});
axios.get(`${API_BASE_URL}/objet?id=${identifiant}`).then((response) => {
setObject(response.data[0]);
});
}, [identifiant]);
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50">
@ -37,10 +46,10 @@ function Objet() {
Tableau de bord - {object.name}
</h2>
</div>
<div className="grid md:grid-cols-3 gap-8 mb-5">
{(!afficherModif) ? (
<div className="grid md:grid-cols-1 lg:grid-cols-3 gap-8 mb-5">
{!afficherModif ? (
<InfoObjet object={object} defafficherModif={defafficherModif} />
):(
) : (
<ModifObject object={object} defafficherModif={defafficherModif} />
)}
@ -62,10 +71,14 @@ function Objet() {
AffPressionGraph={AffPressionGraph}
defAffHumiditeGraph={defAffHumideGraph}
AffHumiditeGraph={AffHumiditeGraph}
tempGraphRef={tempGraphRef}
pressureGraphRef={pressureGraphRef}
humidityGraphRef={humidityGraphRef}
/>
) : (
<p>Chargement des données...</p>
)}
<BatterieInfo object={object} />
</div>
{AffWindGraph &&
(object && object.id ? (
@ -75,13 +88,21 @@ function Objet() {
))}
{AffTempGraph &&
(object && object.id ? (
<MeteoGraph object={object} categorie={"temperature"} Logo={Thermometer}/>
<MeteoGraph
object={object}
categorie={"temperature"}
Logo={Thermometer}
/>
) : (
<p>Chargement des données...</p>
))}
{AffPressionGraph &&
(object && object.id ? (
<MeteoGraph object={object} categorie={"pressure"} Logo={CircleGauge}/>
<MeteoGraph
object={object}
categorie={"pressure"}
Logo={CircleGauge}
/>
) : (
<p>Chargement des données...</p>
))}

View File

@ -7,15 +7,6 @@ function Home() {
const [searchQuery, setSearchQuery] = useState('');
const [activeFilter, setActiveFilter] = useState('all');
const [name, setName] = useState([]);
useEffect(()=> {
axios.get('http://localhost:8888?name=bob')
.then(response => {
setName(response.data.name);
})
.catch(error => {
console.error('There was an error!', error);
});
},[]);
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">