refact & cleanup : Sidebar, Button, card, EmptyState, Loader, ServiceObject, StatusBadge, UptameObject, BackupWidget, SecurityWidget, ServicesWidget, SupportCtaWidget, UptimeWidget, DashboardLayout

This commit is contained in:
LathanDevers
2026-07-29 22:50:04 +02:00
parent 438d739b1a
commit ec900efe3a
42 changed files with 3357 additions and 3966 deletions
+33 -93
View File
@@ -1,99 +1,39 @@
import { useState, useEffect } from 'react';
import { pb } from '../../config/pocketbase';
interface InfrastructureNode {
id: string;
label: string;
type: string;
status: string;
uptime_sla: string;
}
import { useInfrastructureNodes } from '@/hooks/useInfrastructureNodes';
import { UptimeObject } from '@/components/ui/UptimeObject';
import { Card, CardContent } from '@/components/ui/Card';
import { Loader } from '@/components/ui/Loader';
import { EmptyState } from '@/components/ui/EmptyState';
export default function UptimeWidget() {
const [nodes, setNodes] = useState<InfrastructureNode[]>([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchNodes = async () => {
try {
// Récupération sécurisée filtrée automatiquement par le Token JWT de la compagnie
const records = await pb.collection('aegis_infrastructure_nodes').getFullList<InfrastructureNode>({
sort: 'created',
});
setNodes(records);
} catch (error) {
console.error("Erreur lors de la récupération des nœuds :", error);
} finally {
setIsLoading(false);
}
};
fetchNodes();
}, []);
// Fonction pour adapter dynamiquement la couleur du badge selon le statut renvoyé par la base
const getStatusStyle = (status: string) => {
switch (status) {
case 'Opérationnel':
return {
bg: 'bg-emerald-50 text-emerald-600 border-emerald-100',
dot: 'bg-emerald-500'
};
case 'Dégradé':
return {
bg: 'bg-amber-50 text-amber-600 border-amber-100',
dot: 'bg-amber-500'
};
case 'Hors Ligne':
return {
bg: 'bg-red-50 text-red-600 border-red-100',
dot: 'bg-red-500'
};
default:
return {
bg: 'bg-slate-50 text-slate-600 border-slate-100',
dot: 'bg-slate-400'
};
}
};
const { nodes, isLoading, error } = useInfrastructureNodes();
return (
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-6 flex flex-col">
<h2 className="text-lg font-semibold text-slate-900 mb-4">État des Services & SLA</h2>
{isLoading ? (
<div className="flex-1 flex justify-center items-center py-8">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-slate-900"></div>
</div>
) : nodes.length === 0 ? (
<div className="flex-1 flex justify-center items-center py-8 text-sm text-slate-500 italic">
Aucun équipement enregistré pour ce contrat.
</div>
) : (
<div className="divide-y divide-slate-100 flex-1">
{nodes.map((node) => {
const style = getStatusStyle(node.status);
return (
<div key={node.id} className="py-4 flex items-center justify-between first:pt-0 last:pb-0">
<div>
<p className="font-medium text-slate-900">{node.label}</p>
<p className="text-xs text-slate-500 mt-0.5">{node.type}</p>
</div>
<div className="flex items-center space-x-6">
<div className="text-right">
<p className="text-xs text-slate-500">SLA</p>
<p className="text-sm font-semibold text-slate-900">{node.uptime_sla}%</p>
</div>
<div className={`${style.bg} px-3 py-1 rounded-full text-xs font-medium flex items-center border`}>
<div className={`w-1.5 h-1.5 rounded-full ${style.dot} mr-2`}></div>
{node.status}
</div>
</div>
</div>
);
})}
</div>
)}
</div>
<Card>
<CardContent className="p-6 flex flex-col h-full">
<h2 className="text-lg font-semibold text-slate-900 mb-4">État des Services & SLA</h2>
{/* 1. Gestion de l'erreur */}
{error && (
<EmptyState message={error} className="text-red-500 not-italic font-medium" />
)}
{/* 2. Gestion du chargement */}
{isLoading && !error && <Loader />}
{/* 3. Gestion de l'état vide */}
{!isLoading && !error && nodes.length === 0 && (
<EmptyState message="Aucun équipement enregistré pour ce contrat." />
)}
{/* 4. Affichage des données */}
{!isLoading && !error && nodes.length > 0 && (
<div className="divide-y divide-slate-100 flex-1">
{nodes.map((node) => (
<UptimeObject key={node.id} node={node} />
))}
</div>
)}
</CardContent>
</Card>
);
}