feat: Migration complète vers Quarkus PrimeFaces Freya

Migration du frontend React/Next.js vers Quarkus + PrimeFaces Freya 5.0.0

Dashboard:
- Extension de BtpXpressApiClient avec tous les endpoints dashboard
- Création de DashboardService pour récupérer les données API
- Refactorisation DashboardView : uniquement données réelles de l'API
- Restructuration dashboard.xhtml avec tous les aspects métiers BTP
- Suppression complète de toutes les données fictives

Topbar:
- Amélioration du menu profil utilisateur avec header professionnel
- Ajout UserSessionBean pour gérer les informations utilisateur
- Styles CSS personnalisés pour une disposition raffinée
- Badges de notifications conditionnels

Configuration:
- Intégration du thème Freya 5.0.0-jakarta
- Configuration OIDC pour Keycloak (security.lions.dev)
- Gestion des erreurs HTTP 431 (headers size)
- Support du format Fcfa avec séparateurs d'espaces

Converters:
- Création de FcfaConverter pour formater les montants en Fcfa avec espaces (x xxx xxx format)

Code Quality:
- Code entièrement documenté en français avec Javadoc exemplaire
- Respect du principe Java 'Write once, use many times'
- Logging complet pour le débogage
- Gestion d'erreurs robuste
This commit is contained in:
dahoud
2025-11-01 19:55:30 +00:00
commit b749f2df37
269 changed files with 29252 additions and 0 deletions

View File

@@ -0,0 +1,330 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/template.xhtml">
<ui:define name="title">Tableau de bord - BTP Xpress</ui:define>
<ui:define name="head">
<h:outputScript name="chartjs/chart.js" library="demo" />
<script>
//<![CDATA[
$(function(){
var ctx1 = document.getElementById("chartChantiers");
if (ctx1) {
var chartChantiers = new Chart(ctx1.getContext('2d'), {
type: 'line',
data: {
labels: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin'],
datasets: [{
label: 'Chantiers',
data: [12, 19, 15, 25, 22, 28],
borderColor: '#464DF2',
borderWidth: 3,
fill: true,
backgroundColor: 'rgba(70, 77, 242, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: { y: { beginAtZero: true } }
}
});
}
});
//]]>
</script>
</ui:define>
<ui:define name="content">
<div class="layout-dashboard">
<div class="grid">
<!-- KPI Cards - Vue d'ensemble -->
<div class="col-12">
<div class="grid" style="margin: -1rem;">
<div class="col-12 md:col-3">
<div class="card overview-box white">
<div class="overview-info">
<h6>Chantiers actifs</h6>
<h1>#{dashboardView.chantiersActifs}</h1>
<p class="subtitle">Sur #{dashboardView.nombreChantiers} au total</p>
</div>
<i class="pi pi-building"></i>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card overview-box blue">
<div class="overview-info">
<h6>Clients</h6>
<h1>#{dashboardView.nombreClients}</h1>
<p class="subtitle">Actifs</p>
</div>
<i class="pi pi-users"></i>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card overview-box orange">
<div class="overview-info">
<h6>Devis en attente</h6>
<h1>#{dashboardView.nombreDevis}</h1>
<p class="subtitle">À traiter</p>
</div>
<i class="pi pi-file-edit"></i>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card overview-box red">
<div class="overview-info">
<h6>Factures impayées</h6>
<h1>#{dashboardView.facturesImpayees}</h1>
<p class="subtitle">Attention requise</p>
</div>
<i class="pi pi-exclamation-triangle"></i>
</div>
</div>
</div>
</div>
<!-- Alertes critiques -->
<p:outputPanel rendered="#{dashboardView.alerteCritique}" styleClass="col-12">
<div class="card" style="background: #fff3cd; border-left: 4px solid #ffc107;">
<div class="grid align-items-center">
<div class="col">
<h5 style="margin: 0; color: #856404;">
<i class="pi pi-exclamation-triangle"></i>
Alertes critiques : #{dashboardView.totalAlertes}
</h5>
<p style="margin: 0.5rem 0 0 0; color: #856404;">
Des actions nécessitent votre attention immédiate
</p>
</div>
<div class="col-auto">
<p:commandButton value="Voir les alertes" icon="pi pi-bell"
outcome="/dashboard/alertes"
styleClass="ui-button-warning"/>
</div>
</div>
</div>
</p:outputPanel>
<!-- Graphiques et métriques financières -->
<div class="col-12 lg:col-8">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Évolution des chantiers</h6>
<p class="subtitle">Sur 6 mois</p>
</div>
</div>
<canvas id="chartChantiers" style="max-height: 300px;"></canvas>
</div>
</div>
<div class="col-12 lg:col-4">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Chiffre d'affaires</h6>
<p class="subtitle">Ce mois</p>
</div>
</div>
<div class="statistic-item">
<h1 style="margin: 0;">
<h:outputText value="#{dashboardView.chiffreAffairesMois}">
<f:converter converterId="fcfaConverter"/>
</h:outputText>
<h:outputText value=" Fcfa"/>
</h1>
<p style="color: var(--text-color-secondary); margin-top: 0.5rem;">
<i class="pi pi-info-circle"></i>
Données réelles de l'API
</p>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<div class="card-header">
<div class="card-title">
<h6>Budget consommé</h6>
<p class="subtitle">Sur #{dashboardView.budgetTotal} Fcfa</p>
</div>
</div>
<div class="statistic-item">
<p:progressBar value="#{dashboardView.tauxConsommationBudget}"
showValue="true"
styleClass="ui-progressbar-#{dashboardView.tauxConsommationBudget > 80 ? 'warn' : 'success'}"/>
<p style="color: var(--text-color-secondary); margin-top: 0.5rem;">
<h:outputText value="#{dashboardView.budgetConsomme}">
<f:converter converterId="fcfaConverter"/>
</h:outputText>
<h:outputText value=" Fcfa consommés"/>
</p>
</div>
</div>
</div>
<!-- Ressources : Employés, Équipes, Matériel -->
<div class="col-12 lg:col-4">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Ressources humaines</h6>
<p class="subtitle">Employés et équipes</p>
</div>
</div>
<div class="grid" style="gap: 1rem;">
<div class="col-12">
<div class="flex align-items-center justify-content-between">
<span><i class="pi pi-users"></i> Employés</span>
<strong>#{dashboardView.nombreEmployes}</strong>
</div>
</div>
<div class="col-12">
<div class="flex align-items-center justify-content-between">
<span><i class="pi pi-users"></i> Équipes</span>
<strong>#{dashboardView.nombreEquipes}</strong>
</div>
<p:progressBar value="#{dashboardView.nombreEquipes > 0 ? (dashboardView.equipesDisponibles * 100 / dashboardView.nombreEquipes) : 0}"
showValue="true"
styleClass="ui-progressbar-info"/>
<small style="color: var(--text-color-secondary);">
#{dashboardView.equipesDisponibles} disponibles
</small>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-4">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Matériel</h6>
<p class="subtitle">Équipements disponibles</p>
</div>
</div>
<div class="grid" style="gap: 1rem;">
<div class="col-12">
<div class="flex align-items-center justify-content-between">
<span><i class="pi pi-wrench"></i> Total matériel</span>
<strong>#{dashboardView.nombreMateriel}</strong>
</div>
<p:progressBar value="#{dashboardView.nombreMateriel > 0 ? (dashboardView.materielDisponible * 100 / dashboardView.nombreMateriel) : 0}"
showValue="true"
styleClass="ui-progressbar-success"/>
<small style="color: var(--text-color-secondary);">
#{dashboardView.materielDisponible} disponibles
</small>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-4">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Maintenance</h6>
<p class="subtitle">État des maintenances</p>
</div>
</div>
<div class="grid" style="gap: 1rem;">
<div class="col-12">
<div class="flex align-items-center justify-content-between">
<span><i class="pi pi-exclamation-circle" style="color: red;"></i> En retard</span>
<strong style="color: red;">#{dashboardView.maintenancesEnRetard}</strong>
</div>
</div>
<div class="col-12">
<div class="flex align-items-center justify-content-between">
<span><i class="pi pi-calendar"></i> Planifiées</span>
<strong>#{dashboardView.maintenancesPlanifiees}</strong>
</div>
</div>
<div class="col-12">
<p:commandButton value="Voir les maintenances" icon="pi pi-cog"
outcome="/maintenance"
styleClass="ui-button-text" style="width: 100%;"/>
</div>
</div>
</div>
</div>
<!-- Chantiers récents -->
<div class="col-12 lg:col-8">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Chantiers récents</h6>
<p class="subtitle">Derniers chantiers actifs</p>
</div>
<p:commandButton value="Voir tout" icon="pi pi-arrow-right"
outcome="/chantiers"
styleClass="ui-button-text"/>
</div>
<p:dataTable value="#{dashboardView.chantiersRecents}" var="chantier"
emptyMessage="Aucun chantier récent">
<p:column headerText="Nom">
<h:outputText value="#{chantier.nom}"/>
</p:column>
<p:column headerText="Client">
<h:outputText value="#{chantier.client}"/>
</p:column>
<p:column headerText="Date de début">
<h:outputText value="#{chantier.dateDebutFormatee}"/>
</p:column>
<p:column headerText="Avancement">
<p:progressBar value="#{chantier.avancement}"
showValue="true"
styleClass="ui-progressbar-success"/>
</p:column>
<p:column headerText="Actions">
<p:commandButton icon="pi pi-eye" title="Voir les détails"
styleClass="ui-button-text"
outcome="/chantiers/details?id=#{chantier.id}"/>
</p:column>
</p:dataTable>
</div>
</div>
<!-- Chantiers en retard -->
<div class="col-12 lg:col-4">
<div class="card">
<div class="card-header">
<div class="card-title">
<h6>Chantiers en retard</h6>
<p class="subtitle">Attention requise</p>
</div>
</div>
<p:dataList value="#{dashboardView.chantiersEnRetard}" var="chantier"
emptyMessage="Aucun chantier en retard">
<div class="flex align-items-center justify-content-between" style="padding: 0.75rem; border-bottom: 1px solid var(--surface-border);">
<div>
<strong>#{chantier.nom}</strong>
<br/>
<small style="color: var(--text-color-secondary);">
#{chantier.dateFinPrevueFormatee}
</small>
</div>
<p:tag value="+#{chantier.joursRetard}j" severity="danger"/>
</div>
</p:dataList>
<p:outputPanel rendered="#{empty dashboardView.chantiersEnRetard}">
<p style="text-align: center; padding: 1rem; color: var(--text-color-secondary);">
<i class="pi pi-check-circle" style="color: green;"></i>
Aucun chantier en retard
</p>
</p:outputPanel>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>