Amélioration de l'affichage
This commit is contained in:
parent
d229dc9467
commit
b278cb16e1
22
Front-end/src/components/AlertInactive.jsx
Normal file
22
Front-end/src/components/AlertInactive.jsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import { TriangleAlert,X } from "lucide-react";
|
||||||
|
|
||||||
|
function AlertInactive({affAlert,setAffAlert}) {
|
||||||
|
return (
|
||||||
|
(affAlert&&(
|
||||||
|
<div className="flex flex-col md:flex-row bg-slate-600 w-full md:w-1/2 lg:w-1/3 fixed top-20 right-4 rounded-lg p-4 md:p-5 items-center gap-4 md:gap-6 shadow-lg opacity-90">
|
||||||
|
<button onClick={()=>setAffAlert(false)}className="absolute top-2 right-2 text-white hover:text-gray-300">
|
||||||
|
<X/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<TriangleAlert className="text-red-700 w-12 h-12 md:w-16 md:h-16" />
|
||||||
|
|
||||||
|
<p className="text-sm md:text-base text-white text-center md:text-left">
|
||||||
|
Cet objet peut être inactif dû à son manque de données. Vous pouvez le
|
||||||
|
rendre inactif en appuyant <a>ici</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AlertInactive;
|
||||||
@ -6,14 +6,14 @@ function BoutonGraphique({ TypeAff, setAffichage }) {
|
|||||||
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={() => setAffichage(true)}
|
onClick={() => setAffichage(true)}
|
||||||
>
|
>
|
||||||
<ChartLine className="text-red-500" 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={() => setAffichage(false)}
|
onClick={() => setAffichage(false)}
|
||||||
>
|
>
|
||||||
<ChartLine className="text-red-500" size={24} />
|
<ChartLine className="text-indigo-600" size={24} />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,27 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { LogIn, UserPlus } from "lucide-react";
|
import { LogIn, UserPlus, Menu, X } from "lucide-react";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-white shadow-sm">
|
<header className="bg-white shadow-sm">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
|
<div className=" max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
|
||||||
{/* Logo */}
|
|
||||||
<h1 className="text-2xl font-bold text-indigo-600">VigiMétéo</h1>
|
<h1 className="text-2xl font-bold text-indigo-600">VigiMétéo</h1>
|
||||||
|
|
||||||
{/* Navigation */}
|
<button
|
||||||
<nav>
|
className="sm:hidden text-gray-600 hover:text-indigo-600"
|
||||||
<ul className="flex gap-6 text-gray-600">
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||||
|
>
|
||||||
|
{isMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<nav
|
||||||
|
className={`${
|
||||||
|
isMenuOpen ? "block" : "hidden"
|
||||||
|
} absolute top-16 left-0 w-full bg-white shadow-md sm:static sm:w-auto sm:flex sm:gap-6 sm:shadow-none`}
|
||||||
|
>
|
||||||
|
<ul className="flex flex-col sm:flex-row gap-4 sm:gap-6 text-gray-600 p-4 sm:p-0">
|
||||||
<li>
|
<li>
|
||||||
<a href="/" className="hover:text-indigo-600">
|
<a href="/" className="hover:text-indigo-600">
|
||||||
Accueil
|
Accueil
|
||||||
@ -26,11 +37,22 @@ function Header() {
|
|||||||
Gestion
|
Gestion
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li className="sm:hidden">
|
||||||
|
<a href="/login" className="hover:text-indigo-600 flex items-center gap-2">
|
||||||
|
<LogIn size={20} />
|
||||||
|
Connexion
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="sm:hidden">
|
||||||
|
<a href="/signup" className="hover:text-indigo-600 flex items-center gap-2">
|
||||||
|
<UserPlus size={20} />
|
||||||
|
Inscription
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* Actions */}
|
<div className="hidden sm:flex gap-4">
|
||||||
<div className="flex gap-4">
|
|
||||||
<button className="flex items-center gap-2 text-gray-600 hover:text-indigo-600">
|
<button className="flex items-center gap-2 text-gray-600 hover:text-indigo-600">
|
||||||
<LogIn size={20} />
|
<LogIn size={20} />
|
||||||
<span>Connexion</span>
|
<span>Connexion</span>
|
||||||
|
|||||||
@ -18,7 +18,7 @@ function InfoObject({ object,defafficherModif }) {
|
|||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Type :</p>
|
<p className="text-black-900 font-bold">Type :</p>
|
||||||
<p className="text-gray-600">{object.type}</p>
|
<p className="text-gray-600 capitalize">{object.type}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
@ -28,7 +28,7 @@ function InfoObject({ object,defafficherModif }) {
|
|||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Status :</p>
|
<p className="text-black-900 font-bold">Status :</p>
|
||||||
<p className="text-gray-600">{object.status}</p>
|
<p className="text-gray-600 capitalize">{object.status}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
|
|||||||
@ -33,7 +33,6 @@ function MeteoGraph({ object, categorie, Logo }) {
|
|||||||
});
|
});
|
||||||
return moyenne / rawData.length;
|
return moyenne / rawData.length;
|
||||||
}
|
}
|
||||||
console.log(getAvg());
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={object.id}
|
key={object.id}
|
||||||
@ -81,7 +80,7 @@ function MeteoGraph({ object, categorie, Logo }) {
|
|||||||
stroke="#8884d8"
|
stroke="#8884d8"
|
||||||
activeDot={{ r: 8 }}
|
activeDot={{ r: 8 }}
|
||||||
/>
|
/>
|
||||||
<ReferenceLine y={getAvg()} label="Moy" stroke="red" />
|
<ReferenceLine y={getAvg()} label="Moyenne" stroke="red" />
|
||||||
</LineChart>
|
</LineChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ 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";
|
||||||
|
|
||||||
function MeteoInfos({
|
function MeteoInfos({
|
||||||
object,
|
object,
|
||||||
@ -15,17 +16,24 @@ function MeteoInfos({
|
|||||||
AffHumiditeGraph,
|
AffHumiditeGraph,
|
||||||
}) {
|
}) {
|
||||||
const [rawData, setRawData] = useState([]);
|
const [rawData, setRawData] = useState([]);
|
||||||
|
const [AffAlert,setAffAlert] = 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){
|
||||||
|
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) && (
|
||||||
|
<AlertInactive affAlert={AffAlert} setAffAlert={setAffAlert} />
|
||||||
|
)}
|
||||||
<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">
|
||||||
<Sun className="text-indigo-600" size={24} />
|
<Sun className="text-indigo-600" size={24} />
|
||||||
@ -39,10 +47,10 @@ function MeteoInfos({
|
|||||||
<div className="flex align-items gap-3 w-full justify-between">
|
<div className="flex align-items gap-3 w-full justify-between">
|
||||||
<div className="flex align-items ml-3 gap-2">
|
<div className="flex align-items ml-3 gap-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Thermometer className="text-red-600" size={40} />
|
<Thermometer className="text-indigo-600" size={40} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-start">
|
<div className="flex flex-col items-start">
|
||||||
<h1 className="text-red-600 text-xl font-bold ">
|
<h1 className="text-indigo-600 text-xl font-bold ">
|
||||||
Température
|
Température
|
||||||
</h1>
|
</h1>
|
||||||
<h1 className="text-gray-700 text-4xl font-bold">
|
<h1 className="text-gray-700 text-4xl font-bold">
|
||||||
@ -62,10 +70,10 @@ function MeteoInfos({
|
|||||||
<div className="flex align-items gap-3 w-full justify-between">
|
<div className="flex align-items gap-3 w-full justify-between">
|
||||||
<div className="flex align-items ml-3 gap-2">
|
<div className="flex align-items ml-3 gap-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<CircleGauge className="text-red-600" size={40} />
|
<CircleGauge className="text-indigo-600" size={40} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-start">
|
<div className="flex flex-col items-start">
|
||||||
<h1 className="text-red-600 text-xl font-bold ">
|
<h1 className="text-indigo-600 text-xl font-bold ">
|
||||||
Pression
|
Pression
|
||||||
</h1>
|
</h1>
|
||||||
<h1 className="text-gray-700 text-4xl font-bold">
|
<h1 className="text-gray-700 text-4xl font-bold">
|
||||||
@ -85,10 +93,10 @@ function MeteoInfos({
|
|||||||
<div className="flex align-items gap-3 w-full justify-between">
|
<div className="flex align-items gap-3 w-full justify-between">
|
||||||
<div className="flex align-items ml-3 gap-2">
|
<div className="flex align-items ml-3 gap-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Droplet className="text-red-600" size={40} />
|
<Droplet className="text-indigo-600" size={40} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-start">
|
<div className="flex flex-col items-start">
|
||||||
<h1 className="text-red-600 text-xl font-bold ">
|
<h1 className="text-indigo-600 text-xl font-bold ">
|
||||||
Humidité
|
Humidité
|
||||||
</h1>
|
</h1>
|
||||||
<h1 className="text-gray-700 text-4xl font-bold">
|
<h1 className="text-gray-700 text-4xl font-bold">
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { use } from "react";
|
import React, { use } from "react";
|
||||||
import { Info } from "lucide-react";
|
import { Check, Info } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { API_BASE_URL } from "../config";
|
import { API_BASE_URL } from "../config";
|
||||||
@ -9,7 +9,8 @@ function ModifObject({ object,defafficherModif }) {
|
|||||||
const [type, setType] = useState(object.type || "");
|
const [type, setType] = useState(object.type || "");
|
||||||
const [location, setLocalisation] = useState(object.location || "");
|
const [location, setLocalisation] = useState(object.location || "");
|
||||||
const [status, setStatus] = useState(object.status || "");
|
const [status, setStatus] = useState(object.status || "");
|
||||||
const [response, setResponse] = useState(null);
|
const [Response, setResponse] = useState(null);
|
||||||
|
const [isActive,setActive] = useState(object.status==="active");
|
||||||
|
|
||||||
function makeChange() {
|
function makeChange() {
|
||||||
axios
|
axios
|
||||||
@ -18,7 +19,7 @@ function ModifObject({ object,defafficherModif }) {
|
|||||||
description: description,
|
description: description,
|
||||||
type: type,
|
type: type,
|
||||||
location: location,
|
location: location,
|
||||||
status: status
|
status: status,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
setResponse(response.data[0]);
|
setResponse(response.data[0]);
|
||||||
@ -39,7 +40,13 @@ function ModifObject({ object,defafficherModif }) {
|
|||||||
setLocalisation(event.target.value);
|
setLocalisation(event.target.value);
|
||||||
}
|
}
|
||||||
function handleStatusChange(event) {
|
function handleStatusChange(event) {
|
||||||
setStatus(event.target.value);
|
setActive((prevIsActive) => {
|
||||||
|
const newIsActive = !prevIsActive;
|
||||||
|
const newStatus = newIsActive ? "active" : "inactive";
|
||||||
|
console.log(newStatus);
|
||||||
|
setStatus(newStatus);
|
||||||
|
return newIsActive;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
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">
|
||||||
@ -47,31 +54,86 @@ function ModifObject({ object,defafficherModif }) {
|
|||||||
<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">
|
||||||
<Info className="text-indigo-600" size={24} />
|
<Info className="text-indigo-600" size={24} />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-black text-2xl font-bold mb-1 ">Modifier les infos</h1>
|
<h1 className="text-black text-2xl font-bold mb-1 ">
|
||||||
|
Modifier les infos
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Description :</p>
|
<p className="text-black-900 font-bold">Description :</p>
|
||||||
<input className="text-gray-600 border" type="text" value={description} onChange={handleDescriptionChange}/>
|
<input
|
||||||
|
className="text-gray-600 border"
|
||||||
|
type="text"
|
||||||
|
value={description}
|
||||||
|
onChange={handleDescriptionChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Type :</p>
|
<p className="text-black-900 font-bold">Type :</p>
|
||||||
<input className="text-gray-600 border" type="text" value={type} onChange={handleTypeChange}/>
|
<input
|
||||||
|
className="text-gray-600 border"
|
||||||
|
type="text"
|
||||||
|
value={type}
|
||||||
|
onChange={handleTypeChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Localisation :</p>
|
<p className="text-black-900 font-bold">Localisation :</p>
|
||||||
<input className="text-gray-600 border" type="text" value={location} onChange={handleLocalisationChange}/>
|
<input
|
||||||
|
className="text-gray-600 border"
|
||||||
|
type="text"
|
||||||
|
value={location}
|
||||||
|
onChange={handleLocalisationChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<p className="text-black-900 font-bold">Status :</p>
|
<p className="text-black-900 font-bold">Status :</p>
|
||||||
<input className="text-gray-600 border" type="text" value={status} onChange={handleStatusChange}/>
|
<div class="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">
|
||||||
|
<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"
|
||||||
|
/>
|
||||||
|
<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>
|
||||||
<div className="flex items-center gap-4 mb-1">
|
<div className="flex items-center gap-4 mb-1">
|
||||||
<a className="text-blue-500 hover:cursor-pointer" onClick={(()=>makeChange())}>Confirmer les modifs</a>
|
<a
|
||||||
<a className="text-blue-500 hover:cursor-pointer" onClick={(()=>cancelChange())}>Annuler les modifs</a>
|
className="text-blue-500 hover:cursor-pointer"
|
||||||
|
onClick={() => makeChange()}
|
||||||
|
>
|
||||||
|
Confirmer les modifs
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="text-blue-500 hover:cursor-pointer"
|
||||||
|
onClick={() => cancelChange()}
|
||||||
|
>
|
||||||
|
Annuler les modifs
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,6 +3,7 @@ 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";
|
||||||
|
|
||||||
function WindInfo({ object, defAffWindGraph, AffWindGraph }) {
|
function WindInfo({ object, defAffWindGraph, AffWindGraph }) {
|
||||||
const [rawData, setRawData] = useState([]);
|
const [rawData, setRawData] = useState([]);
|
||||||
@ -18,52 +19,40 @@ function WindInfo({ object, defAffWindGraph, AffWindGraph }) {
|
|||||||
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">
|
||||||
<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">
|
||||||
<Wind className="text-indigo-600" size={24} />
|
<Wind className="text-indigo-600" size={24} />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-black text-2xl font-bold mb-1 ">Vent actuel</h1>
|
<h1 className="text-black text-2xl font-bold">Vent actuel</h1>
|
||||||
</div>
|
</div>
|
||||||
{lastData ? (
|
{lastData ? (
|
||||||
<div className="flex flex-col items-center gap-4">
|
<div className="flex flex-col items-center gap-1">
|
||||||
<div className="flex flex-row gap-4">
|
|
||||||
<div className="flex flex-col items-center g-2">
|
|
||||||
<img
|
<img
|
||||||
src={`./src/img/${lastData.wind_direction}.png`}
|
src={`./src/img/${lastData.wind_direction}.png`}
|
||||||
alt="Wind Direction"
|
alt="Wind Direction"
|
||||||
className="h-45"
|
className="h-25"
|
||||||
/>
|
/>
|
||||||
<h1 className="text-gray-600 text-xl font-bold mb-1 ">
|
<h1 className="text-gray-600 text-xl font-bold mb-1 ">
|
||||||
{lastData.wind_direction}
|
{lastData.wind_direction}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
<div className="bg-indigo-50 rounded-lg flex flex-col items-center mb-1 w-full">
|
||||||
<div className="flex flex-col items-center gap-4">
|
<div className="flex align-items gap-3 w-full justify-between">
|
||||||
<div className="flex align-items gap-1">
|
<div className="flex align-items ml-3 gap-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Wind className="text-red-600" size={24} />
|
<Wind className="text-indigo-600" size={40} />
|
||||||
</div>
|
|
||||||
<h1 className="text-red-600 text-xl font-bold ">Valeur</h1>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-col items-start">
|
||||||
|
<h1 className="text-indigo-600 text-xl font-bold ">Valeur</h1>
|
||||||
<h1 className="text-gray-700 text-4xl font-bold">
|
<h1 className="text-gray-700 text-4xl font-bold">
|
||||||
{lastData.wind_speed} <span className="text-lg">km/h</span>
|
{lastData.wind_speed} <span className="text-lg">Km/h</span>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!AffWindGraph ? (
|
<BoutonGraphique
|
||||||
<button
|
TypeAff={AffWindGraph}
|
||||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 mt-4 px-4 rounded-full"
|
setAffichage={defAffWindGraph}
|
||||||
onClick={() => defAffWindGraph(true)}
|
/>
|
||||||
>
|
</div>
|
||||||
Afficher l'historique
|
</div>
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 mt-4 px-4 rounded-full"
|
|
||||||
onClick={() => defAffWindGraph(false)}
|
|
||||||
>
|
|
||||||
Masquer l'historique
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<h1 className="text-gray-500 text-sm">
|
<h1 className="text-gray-500 text-sm">
|
||||||
Dernier enregistrement : {lastData.timestamp}
|
Dernier enregistrement : {lastData.timestamp}
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@ -22,7 +22,7 @@ function Gestion() {
|
|||||||
Bienvenue dans le module <b>Gestion</b>.
|
Bienvenue dans le module <b>Gestion</b>.
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||||
Ce module vous permet de gérer les objets connectés de l'hôpital de manière simple et efficace.
|
Ce module vous permet de gérer les capteur et stations connectés de France de manière simple et efficace.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -14,12 +14,34 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useFetcher } from "react-router-dom";
|
|
||||||
|
|
||||||
function ObjectManagement() {
|
function ObjectManagement() {
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [activeFilter, setActiveFilter] = useState("all");
|
const [activeFilter, setActiveFilter] = useState("");
|
||||||
const [objects, setObjects] = useState([]);
|
const [objects, setObjects] = useState([]);
|
||||||
|
|
||||||
|
const filteredDATA = objects.filter((node) => {
|
||||||
|
const matchesSearchQuery =
|
||||||
|
searchQuery === "" ||
|
||||||
|
node.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
node.description.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
|
|
||||||
|
const matchesTag =
|
||||||
|
activeFilter === "" ||
|
||||||
|
node.name.toLowerCase().includes(activeFilter.toLowerCase()) ||
|
||||||
|
node.description.includes(activeFilter.toLowerCase())||
|
||||||
|
(activeFilter=== "Active" && node.status.toLowerCase()==="active")||
|
||||||
|
(activeFilter=== "Inactive" && node.status.toLowerCase()==="inactive");
|
||||||
|
return matchesSearchQuery && matchesTag;
|
||||||
|
|
||||||
|
});
|
||||||
|
const handleSearchChange = (event) => {
|
||||||
|
setSearchQuery(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTagFilterChange = (selectedTags) => {
|
||||||
|
setFilterTags(selectedTags);
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
axios.get("http://localhost:8888/objets").then((response) => {
|
axios.get("http://localhost:8888/objets").then((response) => {
|
||||||
setObjects(response.data);
|
setObjects(response.data);
|
||||||
@ -49,9 +71,9 @@ function ObjectManagement() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4 mt-4 justify-center">
|
<div className="flex gap-4 mt-4 justify-center">
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("all")}
|
onClick={() => setActiveFilter("")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg ${
|
||||||
activeFilter === "all"
|
activeFilter === ""
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
@ -59,19 +81,9 @@ function ObjectManagement() {
|
|||||||
Tout
|
Tout
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("locations")}
|
onClick={() => setActiveFilter("Station")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg ${
|
||||||
activeFilter === "locations"
|
activeFilter === "Station"
|
||||||
? "bg-indigo-600 text-white"
|
|
||||||
: "bg-white text-gray-600"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
Villes
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => setActiveFilter("events")}
|
|
||||||
className={`px-4 py-2 rounded-lg ${
|
|
||||||
activeFilter === "events"
|
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
@ -79,29 +91,66 @@ function ObjectManagement() {
|
|||||||
Station météo
|
Station météo
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveFilter("transport")}
|
onClick={() => setActiveFilter("Capteur")}
|
||||||
className={`px-4 py-2 rounded-lg ${
|
className={`px-4 py-2 rounded-lg ${
|
||||||
activeFilter === "transport"
|
activeFilter === "Capteur"
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-white text-gray-600"
|
: "bg-white text-gray-600"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Capteur
|
Capteur
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveFilter("Active")}
|
||||||
|
className={`px-4 py-2 rounded-lg ${
|
||||||
|
activeFilter === "Active"
|
||||||
|
? "bg-indigo-600 text-white"
|
||||||
|
: "bg-white text-gray-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Actif
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveFilter("Inactive")}
|
||||||
|
className={`px-4 py-2 rounded-lg ${
|
||||||
|
activeFilter === "Inactive"
|
||||||
|
? "bg-indigo-600 text-white"
|
||||||
|
: "bg-white text-gray-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Inactif
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid md:grid-cols-3 gap-8">
|
<div className="grid md:grid-cols-3 gap-8">
|
||||||
{objects.map(object =>(
|
{filteredDATA.length === 0 ? (
|
||||||
<div key={object.id} className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow">
|
<p>Aucun objet trouvé</p>
|
||||||
|
) : (
|
||||||
|
filteredDATA.map((object) => (
|
||||||
|
<div
|
||||||
|
key={object.id}
|
||||||
|
className="bg-white p-6 rounded-xl shadow-sm hover:shadow-md transition-shadow "
|
||||||
|
>
|
||||||
|
{(object.status==="active")?(
|
||||||
|
<div className="relative w-full">
|
||||||
|
<span className="absolute right-0 flex size-3">
|
||||||
|
<span className="absolute inline-flex h-full w-full rounded-full animate-ping bg-green-400 opacity-75"></span>
|
||||||
|
<span className="relative inline-flex size-3 rounded-full bg-green-500"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
):(
|
||||||
|
<div className="relative w-full">
|
||||||
|
<span className="absolute right-0 flex size-3">
|
||||||
|
<span className="relative inline-flex size-3 rounded-full bg-red-600"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<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">
|
||||||
<RadioTower className="text-indigo-600" size={24} />
|
<RadioTower className="text-indigo-600" size={24} />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-semibold mb-2">
|
<h3 className="text-xl font-semibold mb-2">{object.name}</h3>
|
||||||
{object.name}
|
<p className="text-gray-600 mb-4">{object.description}</p>
|
||||||
</h3>
|
|
||||||
<p className="text-gray-600 mb-4">
|
|
||||||
{object.description}
|
|
||||||
</p>
|
|
||||||
<a
|
<a
|
||||||
href={`/objet?id=${object.id}`}
|
href={`/objet?id=${object.id}`}
|
||||||
className="flex items-center text-indigo-600 hover:text-indigo-700"
|
className="flex items-center text-indigo-600 hover:text-indigo-700"
|
||||||
@ -109,7 +158,8 @@ function ObjectManagement() {
|
|||||||
Plus d'infos <ArrowRight size={16} className="ml-2" />
|
Plus d'infos <ArrowRight size={16} className="ml-2" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { Thermometer, CircleGauge, Droplet } from "lucide-react";
|
|||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useFetcher } from "react-router-dom";
|
|
||||||
import InfoObjet from "../../components/InfoObject";
|
import InfoObjet from "../../components/InfoObject";
|
||||||
import ModifObject from "../../components/ModifObject";
|
import ModifObject from "../../components/ModifObject";
|
||||||
import WindGraph from "../../components/WindGraph";
|
import WindGraph from "../../components/WindGraph";
|
||||||
@ -37,10 +36,9 @@ function Objet() {
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid md:grid-cols-3 gap-8 mb-5">
|
<div className="grid md:grid-cols-3 gap-8 mb-5">
|
||||||
{!afficherModif && (
|
{(!afficherModif) ? (
|
||||||
<InfoObjet object={object} defafficherModif={defafficherModif} />
|
<InfoObjet object={object} defafficherModif={defafficherModif} />
|
||||||
)}
|
):(
|
||||||
{afficherModif && (
|
|
||||||
<ModifObject object={object} defafficherModif={defafficherModif} />
|
<ModifObject object={object} defafficherModif={defafficherModif} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user