Checkpoint: Application Budget Renouvellement SI 2027 Itinova — Version complète avec dashboard KPIs, grille des 75 établissements, panneau de détail par établissement avec tableau de synthèse et liste des équipements filtrables.

This commit is contained in:
Manus
2026-04-01 03:48:42 -04:00
parent 0f673d9ab0
commit 745ea5dce6
14 changed files with 19551 additions and 117 deletions

72
client/src/lib/format.ts Normal file
View File

@@ -0,0 +1,72 @@
// Utilitaires de formatage — Budget SI 2027 Itinova
/**
* Formate un montant en euros avec séparateur de milliers
*/
export function formatEuros(amount: number): string {
return new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(amount);
}
/**
* Formate un nombre avec séparateur de milliers
*/
export function formatNumber(n: number): string {
return new Intl.NumberFormat('fr-FR').format(n);
}
/**
* Retourne la couleur de vétusté selon l'âge
*/
export function getVetusteColor(ageAns: number | null, type: 'fixe' | 'portable'): string {
if (ageAns === null) return 'text-muted-foreground';
const seuil = type === 'fixe' ? 5 : 4;
if (ageAns >= seuil + 2) return 'text-red-600';
if (ageAns >= seuil) return 'text-orange-500';
if (ageAns >= seuil - 1) return 'text-yellow-600';
return 'text-green-600';
}
/**
* Retourne la classe de badge de vétusté
*/
export function getVetusteBadgeClass(ageAns: number | null, type: 'fixe' | 'portable'): string {
if (ageAns === null) return 'bg-gray-100 text-gray-500';
const seuil = type === 'fixe' ? 5 : 4;
if (ageAns >= seuil + 2) return 'bg-red-100 text-red-700 border border-red-200';
if (ageAns >= seuil) return 'bg-orange-100 text-orange-700 border border-orange-200';
if (ageAns >= seuil - 1) return 'bg-yellow-100 text-yellow-700 border border-yellow-200';
return 'bg-green-100 text-green-700 border border-green-200';
}
/**
* Retourne le libellé de vétusté
*/
export function getVetusteLabel(ageAns: number | null, type: 'fixe' | 'portable'): string {
if (ageAns === null) return 'Date inconnue';
const seuil = type === 'fixe' ? 5 : 4;
if (ageAns >= seuil) return `À renouveler (${ageAns.toFixed(1)} ans)`;
return `${ageAns.toFixed(1)} ans`;
}
/**
* Calcule le pourcentage de vétusté pour la barre de progression
*/
export function getVetustePercent(nbRenouveler: number, nbTotal: number): number {
if (nbTotal === 0) return 0;
return Math.round((nbRenouveler / nbTotal) * 100);
}
/**
* Retourne la couleur de la barre de vétusté selon le pourcentage
*/
export function getBarColor(percent: number): string {
if (percent >= 70) return 'bg-red-500';
if (percent >= 40) return 'bg-orange-400';
if (percent >= 20) return 'bg-yellow-400';
return 'bg-green-500';
}