// EtablissementListView.tsx — Vue liste tableau des établissements // Design: Corporate Modernism — Tableau dense avec indicateurs visuels de vétusté import { Monitor, Laptop, ChevronRight, ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react'; import type { Etablissement, SortField, SortOrder } from '../types/budget'; import { formatEuros } from '../lib/format'; interface Props { etablissements: Etablissement[]; onSelect: (etab: Etablissement) => void; sortField: SortField; sortOrder: SortOrder; onSort: (field: SortField) => void; } function SortIcon({ field, sortField, sortOrder }: { field: SortField; sortField: SortField; sortOrder: SortOrder }) { if (sortField !== field) return ; return sortOrder === 'asc' ? : ; } function VetusteBar({ value, total }: { value: number; total: number }) { const pct = total > 0 ? Math.round((value / total) * 100) : 0; const barColor = pct >= 80 ? 'bg-red-500' : pct >= 50 ? 'bg-orange-400' : pct > 0 ? 'bg-yellow-400' : 'bg-emerald-400'; return (
= 80 ? 'text-red-600' : pct >= 50 ? 'text-orange-500' : pct > 0 ? 'text-yellow-600' : 'text-emerald-600'}`}> {value}
{value}/{total}
); } export function EtablissementListView({ etablissements, onSelect, sortField, sortOrder, onSort }: Props) { const thClass = "px-3 py-2.5 text-left text-[11px] font-semibold uppercase tracking-wider text-muted-foreground select-none"; const thSortClass = `${thClass} cursor-pointer hover:text-foreground hover:bg-muted/60 transition-colors`; return (
{etablissements.map((etab, index) => { const nbFixesTotal = etab.fixes?.length ?? 0; const nbPortablesTotal = etab.portables?.length ?? 0; const nbFixesR = etab.stats.nb_fixes_renouveler; const nbPortablesR = etab.stats.nb_portables_renouveler; const totalR = nbFixesR + nbPortablesR; const budget = etab.stats.budget_total; const hasBudget = budget > 0; return ( onSelect(etab)} className={` border-b border-border last:border-0 cursor-pointer transition-colors hover:bg-primary/5 group ${index % 2 === 0 ? 'bg-card' : 'bg-muted/10'} `} > {/* Code */} {/* Nom */} {/* PC Fixes */} {/* PC Portables */} {/* Total à renouveler */} {/* Budget */} {/* Chevron */} ); })}
Code onSort('nom')} >
Établissement
onSort('nb_fixes_renouveler')} style={{ width: '200px' }} >
PC Fixes
onSort('nb_portables_renouveler')} style={{ width: '200px' }} >
PC Portables
Total à renouveler onSort('budget_total')} style={{ width: '130px' }} >
Budget 2027
{etab.code} {etab.nom} {totalR > 0 ? ( {totalR} ) : ( 0 )} {formatEuros(budget)}
{etablissements.length === 0 && (
Aucun établissement correspondant aux critères
)}
); }