Refactoring
This commit is contained in:
@@ -17,6 +17,11 @@
|
||||
<exception-handler-factory>
|
||||
dev.lions.unionflow.client.exception.ViewExpiredExceptionHandlerFactory
|
||||
</exception-handler-factory>
|
||||
|
||||
<!-- ApplicationFactory personnalisé pour configurer l'ELResolverBuilder -->
|
||||
<application-factory>
|
||||
dev.lions.unionflow.client.config.QuarkusApplicationFactory
|
||||
</application-factory>
|
||||
</factory>
|
||||
|
||||
<application>
|
||||
@@ -25,6 +30,10 @@
|
||||
<supported-locale>fr</supported-locale>
|
||||
<supported-locale>en</supported-locale>
|
||||
</locale-config>
|
||||
|
||||
<!-- ELResolver personnalisé pour Quarkus Arc -->
|
||||
<!-- Ce resolver remplace le resolver CDI par défaut qui n'est pas supporté par Arc -->
|
||||
<el-resolver>dev.lions.unionflow.client.el.QuarkusArcELResolver</el-resolver>
|
||||
</application>
|
||||
|
||||
<navigation-rule>
|
||||
|
||||
@@ -53,12 +53,18 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="landing-topbar-right">
|
||||
<ui:include src="/templates/components/buttons/button-primary.xhtml">
|
||||
<ui:param name="value" value="Accéder" />
|
||||
<ui:param name="icon" value="pi pi-arrow-right" />
|
||||
<ui:param name="outcome" value="/pages/secure/dashboard" />
|
||||
<ui:param name="styleClass" value="landing-button" />
|
||||
</ui:include>
|
||||
<a href="#{request.contextPath}/pages/secure/dashboard.xhtml"
|
||||
style="display:inline-flex;align-items:center;gap:.45rem;
|
||||
padding:.5rem 1.25rem;border-radius:6px;
|
||||
border:2px solid rgba(255,255,255,.75);
|
||||
color:#fff;font-size:.875rem;font-weight:700;
|
||||
text-decoration:none;letter-spacing:.02em;
|
||||
transition:background .2s,border-color .2s;"
|
||||
onmouseover="this.style.background='rgba(255,255,255,.18)';this.style.borderColor='#fff'"
|
||||
onmouseout="this.style.background='transparent';this.style.borderColor='rgba(255,255,255,.75)'">
|
||||
Accéder
|
||||
<i class="pi pi-arrow-right" style="font-size:.78rem;"></i>
|
||||
</a>
|
||||
<a href="#" id="landing-menu-button">
|
||||
<i class="pi pi-bars"> </i>
|
||||
</a>
|
||||
@@ -71,12 +77,20 @@
|
||||
<span class="title">UnionFlow</span>
|
||||
<h3>Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs<br/>
|
||||
Simplifiez la gestion de votre organisation avec une solution complète et moderne</h3>
|
||||
<ui:include src="/templates/components/buttons/button-primary.xhtml">
|
||||
<ui:param name="value" value="Accéder à la plateforme" />
|
||||
<ui:param name="icon" value="pi pi-sign-in" />
|
||||
<ui:param name="outcome" value="/pages/secure/dashboard" />
|
||||
<ui:param name="styleClass" value="landing-button" />
|
||||
</ui:include>
|
||||
<a href="#{request.contextPath}/pages/secure/dashboard.xhtml"
|
||||
style="display:inline-flex;align-items:center;gap:.6rem;
|
||||
padding:1rem 2.5rem;border-radius:8px;
|
||||
background:#fff;
|
||||
color:#1e1e2e;
|
||||
font-size:1.05rem;font-weight:800;
|
||||
text-decoration:none;letter-spacing:.01em;
|
||||
box-shadow:0 6px 24px rgba(0,0,0,.25);
|
||||
transition:transform .25s,box-shadow .25s;"
|
||||
onmouseover="this.style.transform='translateY(-3px)';this.style.boxShadow='0 12px 36px rgba(0,0,0,.3)'"
|
||||
onmouseout="this.style.transform='translateY(0)';this.style.boxShadow='0 6px 24px rgba(0,0,0,.25)'">
|
||||
<i class="pi pi-sign-in" style="font-size:.95rem;"></i>
|
||||
Accéder à la plateforme
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -175,57 +189,246 @@
|
||||
<div id="benefits" class="landing-pricing">
|
||||
<div class="section-header">
|
||||
<span class="title">Pourquoi choisir UnionFlow ?</span>
|
||||
<h3>Une solution pensée pour les mutuelles, associations, clubs et organisations similaires avec sécurité avancée, multi-plateforme et synchronisation temps réel.</h3>
|
||||
<h3>Une plateforme robuste et moderne bâtie pour les organisations du monde entier —<br/>
|
||||
avec une sensibilité particulière pour les réalités africaines.</h3>
|
||||
</div>
|
||||
|
||||
<!-- Grille des avantages -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="pricing-card">
|
||||
<h2>Sécurité</h2>
|
||||
<span class="price">100%</span>
|
||||
<span class="time">Sécurisé</span>
|
||||
<ul>
|
||||
<li>Connexion sécurisée et centralisée</li>
|
||||
<li>Contrôle d'accès basé sur les rôles</li>
|
||||
<li>Protection des données sensibles</li>
|
||||
<li>Chiffrement des communications</li>
|
||||
|
||||
<!-- Sécurité de niveau entreprise -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:var(--surface-0);border:1px solid var(--surface-200);border-radius:14px;padding:2rem;box-shadow:0 2px 10px rgba(0,0,0,.06);transition:box-shadow .25s,transform .25s;width:100%;"
|
||||
onmouseover="this.style.boxShadow='0 10px 30px rgba(0,0,0,.12)';this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.boxShadow='0 2px 10px rgba(0,0,0,.06)';this.style.transform='translateY(0)'">
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:var(--blue-50);">
|
||||
<i class="pi pi-shield" style="color:var(--blue-600);font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Sécurité de niveau entreprise
|
||||
</h3>
|
||||
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Authentification centralisée SSO, gestion des accès par rôle et traçabilité
|
||||
complète de toutes les actions sur la plateforme.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
OpenID Connect via Keycloak
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Contrôle d'accès granulaire par rôle
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Chiffrement de bout en bout
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-4 preferred">
|
||||
<div class="pricing-card pro">
|
||||
<span class="preferred-tag">RECOMMANDÉ</span>
|
||||
<h2>Multi-Plateforme</h2>
|
||||
<span class="price">24/7</span>
|
||||
<span class="time">Disponible</span>
|
||||
<ul>
|
||||
<li>Application web responsive</li>
|
||||
<li>Application mobile Flutter</li>
|
||||
<li>iOS et Android</li>
|
||||
<li>Accès depuis n'importe où</li>
|
||||
|
||||
<!-- Multi-plateforme -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:var(--surface-0);border:1px solid var(--surface-200);border-radius:14px;padding:2rem;box-shadow:0 2px 10px rgba(0,0,0,.06);transition:box-shadow .25s,transform .25s;width:100%;"
|
||||
onmouseover="this.style.boxShadow='0 10px 30px rgba(0,0,0,.12)';this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.boxShadow='0 2px 10px rgba(0,0,0,.06)';this.style.transform='translateY(0)'">
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:var(--green-50);">
|
||||
<i class="pi pi-mobile" style="color:var(--green-600);font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Accessible partout, tout le temps
|
||||
</h3>
|
||||
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Une application web responsive et une application mobile native pour
|
||||
que vos gestionnaires et membres restent connectés en toutes circonstances.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Web responsive (tous navigateurs)
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Application mobile iOS & Android
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Disponible 24h/24, 7j/7
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="pricing-card enterprise">
|
||||
<h2>Cloud</h2>
|
||||
<span class="price">Cloud</span>
|
||||
<span class="time">Moderne</span>
|
||||
<ul>
|
||||
<li>Architecture cloud-native</li>
|
||||
<li>Synchronisation temps réel</li>
|
||||
<li>Sauvegarde automatique</li>
|
||||
<li>Scalabilité illimitée</li>
|
||||
|
||||
<!-- Cloud-Native -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:var(--surface-0);border:1px solid var(--surface-200);border-radius:14px;padding:2rem;box-shadow:0 2px 10px rgba(0,0,0,.06);transition:box-shadow .25s,transform .25s;width:100%;"
|
||||
onmouseover="this.style.boxShadow='0 10px 30px rgba(0,0,0,.12)';this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.boxShadow='0 2px 10px rgba(0,0,0,.06)';this.style.transform='translateY(0)'">
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:var(--purple-50);">
|
||||
<i class="pi pi-server" style="color:var(--purple-600);font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Architecture cloud-native
|
||||
</h3>
|
||||
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Bâtie sur Quarkus et une architecture microservices, la plateforme monte en
|
||||
charge automatiquement et garantit une haute disponibilité.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Microservices Quarkus haute performance
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Scalabilité élastique
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Sauvegardes automatisées
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pilotage par la donnée -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:var(--surface-0);border:1px solid var(--surface-200);border-radius:14px;padding:2rem;box-shadow:0 2px 10px rgba(0,0,0,.06);transition:box-shadow .25s,transform .25s;width:100%;"
|
||||
onmouseover="this.style.boxShadow='0 10px 30px rgba(0,0,0,.12)';this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.boxShadow='0 2px 10px rgba(0,0,0,.06)';this.style.transform='translateY(0)'">
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:var(--orange-50);">
|
||||
<i class="pi pi-chart-bar" style="color:var(--orange-600);font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Pilotage par la donnée
|
||||
</h3>
|
||||
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Des tableaux de bord interactifs et des KPIs en temps réel pour prendre
|
||||
les bonnes décisions au bon moment.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Dashboards et KPIs temps réel
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Rapports exportables (PDF, Excel)
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Analyse des tendances et historiques
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Adapté à votre contexte — carte mise en avant -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:linear-gradient(135deg,var(--primary-600) 0%,var(--primary-800) 100%);border-radius:14px;padding:2rem;box-shadow:0 8px 24px rgba(0,0,0,.18);transition:box-shadow .25s,transform .25s;width:100%;position:relative;overflow:hidden;"
|
||||
onmouseover="this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.transform='translateY(0)'">
|
||||
<div style="position:absolute;top:-20px;right:-20px;width:100px;height:100px;border-radius:50%;background:rgba(255,255,255,.07);"></div>
|
||||
<div style="position:absolute;bottom:-30px;right:20px;width:60px;height:60px;border-radius:50%;background:rgba(255,255,255,.05);"></div>
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:rgba(255,255,255,.15);">
|
||||
<i class="pi pi-globe" style="color:#fff;font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:#fff;font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Conçu pour les organisations du monde
|
||||
</h3>
|
||||
<p style="color:rgba(255,255,255,.82);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Mutuelles, clubs Lions, associations sportives, fédérations professionnelles —
|
||||
UnionFlow s'adapte à toute structure, sur tous les continents.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:rgba(255,255,255,.82);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:rgba(255,255,255,.9);"></i>
|
||||
Mutuelles & caisses de solidarité
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:rgba(255,255,255,.82);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:rgba(255,255,255,.9);"></i>
|
||||
Clubs Lions, Rotary, associations civiques
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:rgba(255,255,255,.82);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:rgba(255,255,255,.9);"></i>
|
||||
Fédérations & réseaux multi-niveaux
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Déploiement flexible -->
|
||||
<div class="col-12 md:col-6 lg:col-4 flex">
|
||||
<div style="background:var(--surface-0);border:1px solid var(--surface-200);border-radius:14px;padding:2rem;box-shadow:0 2px 10px rgba(0,0,0,.06);transition:box-shadow .25s,transform .25s;width:100%;"
|
||||
onmouseover="this.style.boxShadow='0 10px 30px rgba(0,0,0,.12)';this.style.transform='translateY(-3px)'"
|
||||
onmouseout="this.style.boxShadow='0 2px 10px rgba(0,0,0,.06)';this.style.transform='translateY(0)'">
|
||||
<div style="width:3rem;height:3rem;border-radius:10px;display:flex;align-items:center;justify-content:center;margin-bottom:1.25rem;background:var(--indigo-50);">
|
||||
<i class="pi pi-cog" style="color:var(--indigo-600);font-size:1.25rem;"></i>
|
||||
</div>
|
||||
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
|
||||
Déploiement selon vos contraintes
|
||||
</h3>
|
||||
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
|
||||
Hébergez la plateforme chez vous ou laissez-nous la gérer. L'API ouverte
|
||||
s'intègre facilement à vos outils existants.
|
||||
</p>
|
||||
<ul style="list-style:none;padding:0;margin:0;">
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
SaaS cloud géré ou on-premise
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
API REST ouverte & documentée
|
||||
</li>
|
||||
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
|
||||
<i class="pi pi-check" style="color:var(--green-500);"></i>
|
||||
Évolutions et support continus
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Bande de chiffres clés -->
|
||||
<div style="background:linear-gradient(135deg,var(--primary-700),var(--primary-900));border-radius:16px;padding:2.5rem 2rem;margin-top:3rem;">
|
||||
<div class="grid text-center" style="color:#fff;">
|
||||
<div class="col-6 md:col-3" style="padding:1rem;">
|
||||
<div style="font-size:2.5rem;font-weight:800;line-height:1;">6+</div>
|
||||
<div style="font-size:.85rem;opacity:.8;margin-top:.5rem;line-height:1.4;">Types d'organisations<br/>supportés</div>
|
||||
</div>
|
||||
<div class="col-6 md:col-3" style="padding:1rem;">
|
||||
<div style="font-size:2.5rem;font-weight:800;line-height:1;">100%</div>
|
||||
<div style="font-size:.85rem;opacity:.8;margin-top:.5rem;line-height:1.4;">Données sécurisées<br/>et chiffrées</div>
|
||||
</div>
|
||||
<div class="col-6 md:col-3" style="padding:1rem;">
|
||||
<div style="font-size:2.5rem;font-weight:800;line-height:1;">24/7</div>
|
||||
<div style="font-size:.85rem;opacity:.8;margin-top:.5rem;line-height:1.4;">Disponibilité<br/>garantie</div>
|
||||
</div>
|
||||
<div class="col-6 md:col-3" style="padding:1rem;">
|
||||
<div style="font-size:2.5rem;font-weight:800;line-height:1;">∞</div>
|
||||
<div style="font-size:.85rem;opacity:.8;margin-top:.5rem;line-height:1.4;">Scalabilité<br/>cloud-native</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5">
|
||||
<ui:include src="/templates/components/buttons/button-primary.xhtml">
|
||||
<ui:param name="value" value="Découvrir toutes les fonctionnalités" />
|
||||
<ui:param name="icon" value="pi pi-arrow-right" />
|
||||
<ui:param name="outcome" value="/pages/secure/dashboard" />
|
||||
<ui:param name="styleClass" value="landing-button" />
|
||||
</ui:include>
|
||||
<a href="#{request.contextPath}/pages/secure/dashboard.xhtml"
|
||||
style="display:inline-flex;align-items:center;gap:.6rem;
|
||||
padding:.95rem 2.25rem;border-radius:8px;
|
||||
background:var(--primary-color,#6366f1);
|
||||
color:var(--primary-color-text,#fff);
|
||||
font-size:1rem;font-weight:700;
|
||||
text-decoration:none;letter-spacing:.02em;
|
||||
box-shadow:0 4px 18px rgba(99,102,241,.35);
|
||||
transition:transform .25s,box-shadow .25s,opacity .2s;"
|
||||
onmouseover="this.style.transform='translateY(-3px)';this.style.boxShadow='0 10px 30px rgba(99,102,241,.5)'"
|
||||
onmouseout="this.style.transform='translateY(0)';this.style.boxShadow='0 4px 18px rgba(99,102,241,.35)'">
|
||||
Accéder à la plateforme
|
||||
<i class="pi pi-arrow-right" style="font-size:.9rem;"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -240,16 +443,16 @@
|
||||
<li><a href="#home">Accueil</a></li>
|
||||
<li><a href="#features">Fonctionnalités</a></li>
|
||||
<li><a href="#benefits">Avantages</a></li>
|
||||
<li><a href="/pages/secure/dashboard">Tableau de Bord</a></li>
|
||||
<li><a href="/pages/secure/dashboard.xhtml">Tableau de Bord</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="footer-menutitle">FONCTIONNALITÉS</span>
|
||||
<ul>
|
||||
<li><a href="/pages/secure/membre/liste">Membres</a></li>
|
||||
<li><a href="/pages/secure/cotisation/historique">Cotisations</a></li>
|
||||
<li><a href="/pages/secure/evenement/calendrier">Événements</a></li>
|
||||
<li><a href="/pages/secure/aide/documentation">Aide</a></li>
|
||||
<li><a href="/pages/secure/membre/liste.xhtml">Membres</a></li>
|
||||
<li><a href="/pages/secure/cotisation/historique.xhtml">Cotisations</a></li>
|
||||
<li><a href="/pages/secure/evenement/calendrier.xhtml">Événements</a></li>
|
||||
<li><a href="/pages/secure/aide/documentation.xhtml">Aide</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -258,22 +461,34 @@
|
||||
<span class="footer-menutitle">CONTACT</span>
|
||||
<ul>
|
||||
<li>support@unionflow.dev</li>
|
||||
<li>Abidjan, Côte d'Ivoire</li>
|
||||
<li>Afrique & International</li>
|
||||
<li>Plateforme de Gestion Intégrée</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-5">
|
||||
<span class="footer-menutitle">NEWSLETTER</span>
|
||||
<span class="footer-subtitle">Rejoignez notre newsletter pour être informé des nouvelles fonctionnalités.</span>
|
||||
<h:form>
|
||||
<div class="newsletter-input">
|
||||
<p:inputText placeholder="adresse email" />
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="S'abonner" />
|
||||
<ui:param name="outlined" value="false" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
<div class="newsletter-input">
|
||||
<input type="email"
|
||||
placeholder="adresse email"
|
||||
style="flex:1;padding:.6rem 1rem;border-radius:6px;
|
||||
border:1px solid rgba(255,255,255,.25);
|
||||
background:rgba(255,255,255,.1);
|
||||
color:#fff;font-size:.875rem;outline:none;"
|
||||
onfocus="this.style.borderColor='rgba(255,255,255,.6)'"
|
||||
onblur="this.style.borderColor='rgba(255,255,255,.25)'" />
|
||||
<button type="button"
|
||||
style="display:inline-flex;align-items:center;gap:.4rem;
|
||||
padding:.6rem 1.25rem;border-radius:6px;
|
||||
background:#fff;color:#1e1e2e;
|
||||
font-size:.875rem;font-weight:700;
|
||||
border:none;cursor:pointer;white-space:nowrap;
|
||||
transition:opacity .2s;"
|
||||
onmouseover="this.style.opacity='.88'"
|
||||
onmouseout="this.style.opacity='1'">
|
||||
S'abonner
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="footer-bottom">
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Gestion des Utilisateurs - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
<!-- En-tête avec disposition Freya stricte -->
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 lg:col-8">
|
||||
<h2 class="text-primary font-bold mb-2">
|
||||
<i class="pi pi-users text-blue-500 mr-2"></i>
|
||||
Gestion des Utilisateurs
|
||||
</h2>
|
||||
<p class="text-600 mt-0">Administration des comptes et permissions utilisateurs</p>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-4 text-right">
|
||||
<h:form id="formActionsEntete">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:commandButton value="Nouvel Utilisateur"
|
||||
icon="pi pi-user-plus"
|
||||
styleClass="ui-button-success ui-button-sm w-full"
|
||||
onclick="PF('dlgNouvelUtilisateur').show();" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:commandButton value="Importer"
|
||||
icon="pi pi-upload"
|
||||
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
|
||||
onclick="PF('dlgImporterUtilisateurs').show();" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:commandButton value="Exporter"
|
||||
icon="pi pi-download"
|
||||
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
|
||||
action="#{utilisateursBean.exporterUtilisateurs}" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques utilisateurs avec Freya stricte -->
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4" style="min-height: 9rem;">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<span class="block text-600 font-medium text-sm">Total Utilisateurs</span>
|
||||
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
|
||||
style="width: 2.5rem; height: 2.5rem;">
|
||||
<i class="pi pi-users text-blue-600 text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.totalUtilisateurs}</div>
|
||||
<div class="flex align-items-center mb-2">
|
||||
<div class="bg-blue-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
|
||||
<span class="text-500 text-xs">Comptes actifs</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4" style="min-height: 9rem;">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<span class="block text-600 font-medium text-sm">Connectés</span>
|
||||
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
|
||||
style="width: 2.5rem; height: 2.5rem;">
|
||||
<i class="pi pi-circle-fill text-green-600 text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.utilisateursConnectes}</div>
|
||||
<div class="flex align-items-center mb-2">
|
||||
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
|
||||
<span class="text-500 text-xs">En ligne maintenant</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4" style="min-height: 9rem;">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<span class="block text-600 font-medium text-sm">Administrateurs</span>
|
||||
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
|
||||
style="width: 2.5rem; height: 2.5rem;">
|
||||
<i class="pi pi-shield text-orange-600 text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.administrateurs}</div>
|
||||
<div class="flex align-items-center mb-2">
|
||||
<div class="bg-orange-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
|
||||
<span class="text-500 text-xs">Privilèges élevés</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4" style="min-height: 9rem;">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<span class="block text-600 font-medium text-sm">Désactivés</span>
|
||||
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
|
||||
style="width: 2.5rem; height: 2.5rem;">
|
||||
<i class="pi pi-ban text-red-600 text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.utilisateursDesactives}</div>
|
||||
<div class="flex align-items-center mb-2">
|
||||
<div class="bg-red-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
|
||||
<span class="text-500 text-xs">Comptes suspendus</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtres et recherche avec Freya stricte -->
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4">
|
||||
<h5 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-search text-blue-500 mr-2"></i>
|
||||
Recherche et Filtres
|
||||
</h5>
|
||||
<h:form id="formFiltres">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="searchNom" value="Nom ou Email" />
|
||||
<p:inputText id="searchNom" value="#{utilisateursBean.filtres.recherche}"
|
||||
placeholder="Rechercher par nom ou email...">
|
||||
<p:ajax event="keyup" update="dtUtilisateurs" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="filterRole" value="Rôle" />
|
||||
<p:selectOneMenu id="filterRole" value="#{utilisateursBean.filtres.role}">
|
||||
<f:selectItem itemLabel="Tous les rôles" itemValue="" />
|
||||
<f:selectItem itemLabel="Super Admin" itemValue="SUPER_ADMIN" />
|
||||
<f:selectItem itemLabel="Admin" itemValue="ADMIN" />
|
||||
<f:selectItem itemLabel="Gestionnaire" itemValue="GESTIONNAIRE" />
|
||||
<f:selectItem itemLabel="Utilisateur" itemValue="USER" />
|
||||
<p:ajax update="dtUtilisateurs" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="filterStatut" value="Statut" />
|
||||
<p:selectOneMenu id="filterStatut" value="#{utilisateursBean.filtres.statut}">
|
||||
<f:selectItem itemLabel="Tous statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
|
||||
<f:selectItem itemLabel="Suspendu" itemValue="SUSPENDU" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="ATTENTE" />
|
||||
<p:ajax update="dtUtilisateurs" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="filterConnexion" value="Dernière connexion" />
|
||||
<p:selectOneMenu id="filterConnexion" value="#{utilisateursBean.filtres.connexion}">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Aujourd'hui" itemValue="AUJOURD_HUI" />
|
||||
<f:selectItem itemLabel="Cette semaine" itemValue="SEMAINE" />
|
||||
<f:selectItem itemLabel="Ce mois" itemValue="MOIS" />
|
||||
<f:selectItem itemLabel="Plus de 30 jours" itemValue="PLUS_30_JOURS" />
|
||||
<p:ajax update="dtUtilisateurs" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="filterOrganisation" value="Organisation" />
|
||||
<p:selectOneMenu id="filterOrganisation" value="#{utilisateursBean.filtres.organisation}">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItems value="#{utilisateursBean.organisationsDisponibles}"
|
||||
var="org"
|
||||
itemLabel="#{org.nom}"
|
||||
itemValue="#{org.id}" />
|
||||
<p:ajax update="dtUtilisateurs" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<p:commandButton value="Rechercher"
|
||||
icon="pi pi-search"
|
||||
styleClass="ui-button-primary ui-button-sm"
|
||||
action="#{utilisateursBean.rechercher}"
|
||||
update="dtUtilisateurs" />
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
|
||||
action="#{utilisateursBean.reinitialiserFiltres}"
|
||||
update="@form dtUtilisateurs" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Liste des utilisateurs avec Freya stricte -->
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<h5 class="text-900 font-bold m-0">
|
||||
<i class="pi pi-users text-blue-500 mr-2"></i>
|
||||
Utilisateurs (#{utilisateursBean.utilisateursFiltres.size()})
|
||||
</h5>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<h:form id="formActionsGroupees">
|
||||
<p:commandButton value="Actions groupées"
|
||||
icon="pi pi-cog"
|
||||
styleClass="ui-button-outlined ui-button-warning"
|
||||
onclick="PF('dlgActionsGroupees').show();"
|
||||
disabled="#{empty utilisateursBean.utilisateursSelectionnes}" />
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p:dataTable id="dtUtilisateurs"
|
||||
value="#{utilisateursBean.utilisateursFiltres}"
|
||||
var="utilisateur"
|
||||
selection="#{utilisateursBean.utilisateursSelectionnes}"
|
||||
rowKey="#{utilisateur.id}"
|
||||
paginator="true"
|
||||
rows="15"
|
||||
paginatorPosition="both"
|
||||
sortMode="single"
|
||||
styleClass="p-datatable-sm"
|
||||
emptyMessage="Aucun utilisateur trouvé">
|
||||
|
||||
<p:column selectionMode="multiple" width="40" />
|
||||
|
||||
<p:column headerText="Utilisateur" sortBy="#{utilisateur.nom}" width="300">
|
||||
<div class="flex align-items-center">
|
||||
<div class="surface-200 border-circle flex align-items-center justify-content-center mr-3"
|
||||
style="width: 40px; height: 40px;">
|
||||
<i class="pi pi-user text-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-900 font-medium">#{utilisateur.nomComplet}</div>
|
||||
<div class="text-600 text-sm">#{utilisateur.email}</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Rôle" sortBy="#{utilisateur.role}" width="120">
|
||||
<p:tag value="#{utilisateur.roleLibelle}" severity="#{utilisateur.roleSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{utilisateur.organisation}" width="150">
|
||||
<span class="text-900">#{utilisateur.organisationNom}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{utilisateur.statut}" width="100">
|
||||
<p:tag value="#{utilisateur.statutLibelle}" severity="#{utilisateur.statutSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Dernière connexion" sortBy="#{utilisateur.derniereConnexion}" width="140">
|
||||
<div class="text-900 text-sm">#{utilisateur.derniereConnexionFormatee}</div>
|
||||
<div class="text-600 text-xs">#{utilisateur.derniereConnexionRelative}</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date création" sortBy="#{utilisateur.dateCreation}" width="120">
|
||||
<span class="text-900 text-sm">#{utilisateur.dateCreationFormatee}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" width="150">
|
||||
<h:form id="formActions#{utilisateur.id}">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-info"
|
||||
title="Voir profil"
|
||||
onclick="PF('dlgVoirUtilisateur').show();">
|
||||
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
|
||||
</p:commandButton>
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-warning"
|
||||
title="Modifier"
|
||||
onclick="PF('dlgModifierUtilisateur').show();">
|
||||
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
|
||||
</p:commandButton>
|
||||
<p:commandButton icon="pi pi-key"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
|
||||
title="Gérer permissions"
|
||||
onclick="PF('dlgPermissions').show();">
|
||||
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
|
||||
</p:commandButton>
|
||||
<p:commandButton icon="pi pi-ban"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-danger"
|
||||
title="Désactiver"
|
||||
onclick="return confirm('Êtes-vous sûr de vouloir désactiver cet utilisateur ?');"
|
||||
action="#{utilisateursBean.desactiverUtilisateur(utilisateur)}"
|
||||
rendered="#{utilisateur.statut != 'INACTIF'}" />
|
||||
<p:commandButton icon="pi pi-check"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-success"
|
||||
title="Activer"
|
||||
action="#{utilisateursBean.activerUtilisateur(utilisateur)}"
|
||||
rendered="#{utilisateur.statut == 'INACTIF'}" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Nouvel Utilisateur avec Freya stricte -->
|
||||
<p:dialog header="Nouvel Utilisateur" widgetVar="dlgNouvelUtilisateur" modal="true" width="600">
|
||||
<h:form id="formNouvelUtilisateur">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newNom" value="Nom" />
|
||||
<p:inputText id="newNom" value="#{utilisateursBean.nouvelUtilisateur.nom}"
|
||||
required="true" placeholder="Nom de famille" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newPrenom" value="Prénom" />
|
||||
<p:inputText id="newPrenom" value="#{utilisateursBean.nouvelUtilisateur.prenom}"
|
||||
required="true" placeholder="Prénom" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newEmail" value="Email" />
|
||||
<p:inputText id="newEmail" value="#{utilisateursBean.nouvelUtilisateur.email}"
|
||||
required="true" placeholder="adresse@email.com" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newTelephone" value="Téléphone" />
|
||||
<p:inputText id="newTelephone" value="#{utilisateursBean.nouvelUtilisateur.telephone}"
|
||||
placeholder="+225 XX XX XX XX" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newRole" value="Rôle" />
|
||||
<p:selectOneMenu id="newRole" value="#{utilisateursBean.nouvelUtilisateur.role}" required="true">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
|
||||
<f:selectItem itemLabel="👤 Utilisateur" itemValue="USER" />
|
||||
<f:selectItem itemLabel="⚙️ Gestionnaire" itemValue="GESTIONNAIRE" />
|
||||
<f:selectItem itemLabel="🛠️ Administrateur" itemValue="ADMIN" />
|
||||
<f:selectItem itemLabel="🛡️ Super Admin" itemValue="SUPER_ADMIN" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="newOrganisation" value="Organisation" />
|
||||
<p:selectOneMenu id="newOrganisation" value="#{utilisateursBean.nouvelUtilisateur.organisationId}">
|
||||
<f:selectItem itemLabel="Aucune organisation" itemValue="" />
|
||||
<f:selectItems value="#{utilisateursBean.organisationsDisponibles}"
|
||||
var="org"
|
||||
itemLabel="#{org.nom}"
|
||||
itemValue="#{org.id}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="newMotDePasse" value="Mot de passe temporaire" />
|
||||
<p:password id="newMotDePasse" value="#{utilisateursBean.nouvelUtilisateur.motDePasse}"
|
||||
required="true" placeholder="Mot de passe temporaire" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12">
|
||||
<div class="flex align-items-center">
|
||||
<p:selectBooleanCheckbox id="newEnvoyerEmail" value="#{utilisateursBean.nouvelUtilisateur.envoyerEmail}" />
|
||||
<p:outputLabel for="newEnvoyerEmail" value="Envoyer les informations de connexion par email" styleClass="ml-2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<p:commandButton value="Créer l'utilisateur" icon="pi pi-check"
|
||||
styleClass="ui-button-success"
|
||||
action="#{utilisateursBean.creerUtilisateur}"
|
||||
update="@form dtUtilisateurs"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgNouvelUtilisateur').hide();" />
|
||||
<p:commandButton value="Annuler" icon="pi pi-times"
|
||||
styleClass="ui-button-secondary"
|
||||
onclick="PF('dlgNouvelUtilisateur').hide();" type="button" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -209,13 +209,16 @@
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="montantPaye" value="Montant à payer (FCFA)" />
|
||||
<p:inputNumber id="montantPaye"
|
||||
value="#{adhesionsBean.adhesionSelectionnee.montantPaye}"
|
||||
<p:outputLabel for="montantPaiementPartiel" value="Montant à payer (FCFA)" />
|
||||
<p:inputNumber id="montantPaiementPartiel"
|
||||
value="#{adhesionsBean.montantPaiementPartiel}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
maxValue="#{adhesionsBean.adhesionSelectionnee.fraisAdhesion}"
|
||||
styleClass="w-full" />
|
||||
maxValue="#{adhesionsBean.adhesionSelectionnee.montantRestant}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
requiredMessage="Veuillez saisir le montant du paiement partiel" />
|
||||
<p:message for="montantPaiementPartiel" />
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/forms/form-field-select.xhtml">
|
||||
@@ -248,7 +251,7 @@
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerPaiement(adhesionsBean.adhesionSelectionnee.montantPaye, adhesionsBean.adhesionSelectionnee.methodePaiement, adhesionsBean.adhesionSelectionnee.referencePaiement)}" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerPaiementPartiel}" />
|
||||
<ui:param name="update" value="@form :formPaiements" />
|
||||
<ui:param name="oncomplete" value="PF('dlgPaiementPartiel').hide();" />
|
||||
</ui:include>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
<p:column headerText="Date" sortBy="#{sauvegarde.date}">
|
||||
<h:outputText value="#{sauvegarde.date}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy HH:mm"/>
|
||||
<f:convertDateTime pattern="dd/MM/yyyy HH:mm" type="localDateTime"/>
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<p:column headerText="Date approbation" sortBy="#{demande.dateDemande}">
|
||||
<h:outputText value="#{demande.dateDemande}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy"/>
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate"/>
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
<p:column headerText="Date" sortBy="#{demande.dateDemande}">
|
||||
<h:outputText value="#{demande.dateDemande}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy"/>
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate"/>
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
<p:column headerText="Date" sortBy="#{demande.dateDemande}">
|
||||
<h:outputText value="#{demande.dateDemande}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy"/>
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate"/>
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{demandesAideBean}"/>
|
||||
<ui:param name="page" value="#{suggestionBean}"/>
|
||||
<ui:define name="title">Suggestions et Feedback - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
@@ -30,7 +30,8 @@
|
||||
<p:commandButton value="Nouvelle Suggestion"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-plus"
|
||||
onclick="PF('nouvelleSuggestionDialog').show()" />
|
||||
action="#{suggestionBean.ouvrirDialogNouvelleSuggestion}"
|
||||
update="@form" />
|
||||
<p:commandButton value="Mes Suggestions"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-user" />
|
||||
@@ -41,28 +42,28 @@
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">247</div>
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">#{suggestionBean.totalSuggestions}</div>
|
||||
<div class="text-900 font-semibold mb-1">Suggestions</div>
|
||||
<div class="text-600 text-sm">Soumises</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">43</div>
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">#{suggestionBean.suggestionsImplementees}</div>
|
||||
<div class="text-900 font-semibold mb-1">Implémentées</div>
|
||||
<div class="text-600 text-sm">Dans la v2.0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">1,523</div>
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">#{suggestionBean.totalVotes}</div>
|
||||
<div class="text-900 font-semibold mb-1">Votes</div>
|
||||
<div class="text-600 text-sm">Ce mois-ci</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">156</div>
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">#{suggestionBean.contributeursActifs}</div>
|
||||
<div class="text-900 font-semibold mb-1">Contributeurs</div>
|
||||
<div class="text-600 text-sm">Actifs</div>
|
||||
</div>
|
||||
@@ -388,41 +389,48 @@
|
||||
header="Soumettre une Nouvelle Suggestion"
|
||||
modal="true"
|
||||
width="800"
|
||||
styleClass="surface-0">
|
||||
styleClass="surface-0"
|
||||
visible="#{suggestionBean.afficherDialogNouvelleSuggestion}">
|
||||
<h:form id="nouvelleSuggestionForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="categorieSugg" class="block text-900 font-semibold mb-2">Catégorie *</label>
|
||||
<p:selectOneMenu id="categorieSugg" styleClass="w-full">
|
||||
<p:selectOneMenu id="categorieSugg"
|
||||
value="#{suggestionBean.nouvelleSuggestion.categorie}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionnez une catégorie" itemValue="" />
|
||||
<f:selectItem itemLabel="Interface Utilisateur" itemValue="ui" />
|
||||
<f:selectItem itemLabel="Nouvelle Fonctionnalité" itemValue="feature" />
|
||||
<f:selectItem itemLabel="Amélioration Performance" itemValue="performance" />
|
||||
<f:selectItem itemLabel="Sécurité" itemValue="securite" />
|
||||
<f:selectItem itemLabel="Intégration Externe" itemValue="integration" />
|
||||
<f:selectItem itemLabel="Application Mobile" itemValue="mobile" />
|
||||
<f:selectItem itemLabel="Rapports et Analytics" itemValue="reporting" />
|
||||
<f:selectItem itemLabel="Interface Utilisateur" itemValue="UI" />
|
||||
<f:selectItem itemLabel="Nouvelle Fonctionnalité" itemValue="FEATURE" />
|
||||
<f:selectItem itemLabel="Amélioration Performance" itemValue="PERFORMANCE" />
|
||||
<f:selectItem itemLabel="Sécurité" itemValue="SECURITE" />
|
||||
<f:selectItem itemLabel="Intégration Externe" itemValue="INTEGRATION" />
|
||||
<f:selectItem itemLabel="Application Mobile" itemValue="MOBILE" />
|
||||
<f:selectItem itemLabel="Rapports et Analytics" itemValue="REPORTING" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="prioriteSugg" class="block text-900 font-semibold mb-2">Priorité estimée</label>
|
||||
<p:selectOneMenu id="prioriteSugg" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Basse" itemValue="basse" />
|
||||
<f:selectItem itemLabel="Moyenne" itemValue="moyenne" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="haute" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="critique" />
|
||||
<p:selectOneMenu id="prioriteSugg"
|
||||
value="#{suggestionBean.nouvelleSuggestion.prioriteEstimee}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
|
||||
<f:selectItem itemLabel="Moyenne" itemValue="MOYENNE" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="titreSugg" class="block text-900 font-semibold mb-2">Titre de votre suggestion *</label>
|
||||
<p:inputText id="titreSugg"
|
||||
value="#{suggestionBean.nouvelleSuggestion.titre}"
|
||||
placeholder="Résumez votre idée en une phrase claire"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="descriptionSugg" class="block text-900 font-semibold mb-2">Description détaillée *</label>
|
||||
<p:inputTextarea id="descriptionSugg"
|
||||
value="#{suggestionBean.nouvelleSuggestion.description}"
|
||||
rows="6"
|
||||
placeholder="Décrivez votre suggestion : problème rencontré, solution proposée, bénéfices attendus..."
|
||||
styleClass="w-full" />
|
||||
@@ -430,6 +438,7 @@
|
||||
<div class="field col-12">
|
||||
<label for="justificationSugg" class="block text-900 font-semibold mb-2">Justification métier</label>
|
||||
<p:inputTextarea id="justificationSugg"
|
||||
value="#{suggestionBean.nouvelleSuggestion.justification}"
|
||||
rows="3"
|
||||
placeholder="Expliquez pourquoi cette fonctionnalité serait utile et pour quels utilisateurs..."
|
||||
styleClass="w-full" />
|
||||
@@ -447,11 +456,14 @@
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('nouvelleSuggestionDialog').hide()"
|
||||
action="#{suggestionBean.fermerDialogNouvelleSuggestion}"
|
||||
update="@form"
|
||||
type="button" />
|
||||
<p:commandButton value="Soumettre la Suggestion"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-send" />
|
||||
icon="pi pi-send"
|
||||
action="#{suggestionBean.creerSuggestion}"
|
||||
update="@form" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{demandesAideBean}"/>
|
||||
<ui:param name="page" value="#{ticketBean}"/>
|
||||
<ui:define name="title">Mes Tickets Support - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
@@ -30,7 +30,8 @@
|
||||
<p:commandButton value="Nouveau Ticket"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-plus"
|
||||
onclick="PF('nouveauTicketDialog').show()" />
|
||||
action="#{ticketBean.ouvrirDialogNouveauTicket}"
|
||||
update="@form" />
|
||||
<p:commandButton value="FAQ"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-question-circle" />
|
||||
@@ -41,28 +42,28 @@
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">12</div>
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">#{ticketBean.totalTickets}</div>
|
||||
<div class="text-900 font-semibold mb-1">Tickets Créés</div>
|
||||
<div class="text-600 text-sm">Au total</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">3</div>
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">#{ticketBean.ticketsEnAttente}</div>
|
||||
<div class="text-900 font-semibold mb-1">En Attente</div>
|
||||
<div class="text-600 text-sm">Réponse support</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">8</div>
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">#{ticketBean.ticketsResolus}</div>
|
||||
<div class="text-900 font-semibold mb-1">Résolus</div>
|
||||
<div class="text-600 text-sm">Avec succès</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-red-500 mb-2">1</div>
|
||||
<div class="text-2xl font-bold text-red-500 mb-2">#{ticketBean.ticketsFermes}</div>
|
||||
<div class="text-900 font-semibold mb-1">Fermé</div>
|
||||
<div class="text-600 text-sm">Sans résolution</div>
|
||||
</div>
|
||||
@@ -130,191 +131,84 @@
|
||||
Historique de vos Tickets
|
||||
</h4>
|
||||
|
||||
<!-- Ticket 1 - En cours -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<ui:repeat value="#{ticketBean.tickets}" var="ticket">
|
||||
<!-- Ticket dynamique -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200 #{ticket.statut == 'FERME' ? 'opacity-70' : ''}">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-orange-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-clock text-orange-600 text-xl"></i>
|
||||
<div class="w-3rem h-3rem border-circle #{ticket.statut == 'RESOLU' ? 'bg-green-100' : (ticket.statut == 'EN_ATTENTE' ? 'bg-blue-100' : (ticket.statut == 'FERME' ? 'bg-red-100' : 'bg-orange-100'))} flex align-items-center justify-content-center">
|
||||
<i class="pi #{ticket.statut == 'RESOLU' ? 'pi-check' : (ticket.statut == 'EN_ATTENTE' ? 'pi-pause' : (ticket.statut == 'FERME' ? 'pi-times' : 'pi-clock'))} #{ticket.statut == 'RESOLU' ? 'text-green-600' : (ticket.statut == 'EN_ATTENTE' ? 'text-blue-600' : (ticket.statut == 'FERME' ? 'text-red-600' : 'text-orange-600'))} text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#TK-2024-0157 - Problème d'export Excel</h6>
|
||||
<h6 class="text-900 font-semibold mb-1">#{ticket.numeroTicket} - #{ticket.sujet}</h6>
|
||||
<div class="flex align-items-center gap-2 mb-1">
|
||||
<p:tag value="EN COURS" severity="warning" styleClass="text-xs" />
|
||||
<p:tag value="HAUTE" severity="danger" styleClass="text-xs" />
|
||||
<p:tag value="TECHNIQUE" severity="info" styleClass="text-xs" />
|
||||
<p:tag value="#{ticket.statut}"
|
||||
severity="#{ticket.statut == 'RESOLU' ? 'success' : (ticket.statut == 'FERME' ? 'danger' : (ticket.statut == 'EN_ATTENTE' ? 'info' : 'warning'))}"
|
||||
styleClass="text-xs" />
|
||||
<p:tag value="#{ticket.priorite}"
|
||||
severity="#{ticket.priorite == 'URGENTE' or ticket.priorite == 'HAUTE' ? 'danger' : (ticket.priorite == 'NORMALE' ? 'success' : 'secondary')}"
|
||||
styleClass="text-xs" />
|
||||
<p:tag value="#{ticket.categorie}"
|
||||
severity="info"
|
||||
styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-0">Créé le 15 janvier 2024 • Dernière réponse il y a 2h</p>
|
||||
<p class="text-600 text-sm mb-0">
|
||||
Créé le #{ticket.dateCreation != null ? ticket.dateCreation : 'N/A'}
|
||||
#{ticket.dateDerniereReponse != null ? ' • Dernière réponse ' + ticket.dateDerniereReponse : ''}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-600 text-sm mb-2">Agent: Marie Dubois</div>
|
||||
#{ticket.agentNom != null ? '<div class="text-600 text-sm mb-2">Agent: ' + ticket.agentNom + '</div>' : ''}
|
||||
<p:commandButton value="Voir Détails"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-eye" />
|
||||
icon="pi pi-eye"
|
||||
action="#{ticketBean.voirDetails}"
|
||||
update="@form">
|
||||
<f:setPropertyActionListener target="#{ticketBean.ticketSelectionne}" value="#{ticket}" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-3">
|
||||
Impossible d'exporter la liste des membres en format Excel. Le fichier généré est corrompu
|
||||
et ne s'ouvre pas dans Excel. Cela concerne tous les exports depuis la version 2.1.
|
||||
#{ticket.description != null ? ticket.description : 'Aucune description'}
|
||||
</p>
|
||||
#{ticket.resolution != null ? '<div class="surface-green-50 border-left-3 border-green-500 p-3 mb-3"><p class="text-green-700 text-sm mb-0"><i class="pi pi-check-circle mr-2"></i><strong>Résolution:</strong> ' + ticket.resolution + '</p></div>' : ''}
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-comments text-blue-500"></i>
|
||||
<span class="text-600 text-sm">5 messages</span>
|
||||
<i class="pi pi-paperclip text-600 ml-3"></i>
|
||||
<span class="text-600 text-sm">2 fichiers</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-clock text-600"></i>
|
||||
<span class="text-600 text-sm">SLA: 4h restantes</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ticket 2 - En attente -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-pause text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#TK-2024-0143 - Demande de formation personnalisée</h6>
|
||||
<div class="flex align-items-center gap-2 mb-1">
|
||||
<p:tag value="EN ATTENTE" severity="info" styleClass="text-xs" />
|
||||
<p:tag value="NORMALE" severity="success" styleClass="text-xs" />
|
||||
<p:tag value="FONCTIONNALITÉ" severity="help" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-0">Créé le 12 janvier 2024 • En attente de votre réponse</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-600 text-sm mb-2">Agent: Thomas Martin</div>
|
||||
<p:commandButton value="Répondre"
|
||||
styleClass="p-button-primary p-button-sm"
|
||||
icon="pi pi-reply" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-3">
|
||||
Souhaitons organiser une formation sur mesure pour notre équipe administrative.
|
||||
Besoin de devis pour 15 personnes sur 2 jours.
|
||||
</p>
|
||||
<div class="surface-blue-50 border-left-3 border-blue-500 p-3 mb-3">
|
||||
<p class="text-blue-700 text-sm mb-0">
|
||||
<i class="pi pi-info-circle mr-2"></i>
|
||||
<strong>Action requise:</strong> Merci de préciser vos disponibilités pour les dates proposées.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-comments text-blue-500"></i>
|
||||
<span class="text-600 text-sm">3 messages</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-exclamation-triangle text-orange-500"></i>
|
||||
<span class="text-orange-600 text-sm">Réponse attendue depuis 3 jours</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ticket 3 - Résolu -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-check text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#TK-2024-0128 - Problème de connexion mobile</h6>
|
||||
<div class="flex align-items-center gap-2 mb-1">
|
||||
<p:tag value="RÉSOLU" severity="success" styleClass="text-xs" />
|
||||
<p:tag value="BASSE" severity="secondary" styleClass="text-xs" />
|
||||
<p:tag value="TECHNIQUE" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-0">Créé le 8 janvier 2024 • Résolu le 10 janvier 2024</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-600 text-sm mb-2">Agent: Sophie Leroy</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Noter"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-star" />
|
||||
<p:commandButton value="Détails"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-eye" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-3">
|
||||
Application ne se charge pas sur smartphone Android. Écran blanc après connexion.
|
||||
</p>
|
||||
<div class="surface-green-50 border-left-3 border-green-500 p-3 mb-3">
|
||||
<p class="text-green-700 text-sm mb-0">
|
||||
<i class="pi pi-check-circle mr-2"></i>
|
||||
<strong>Résolution:</strong> Problème résolu en vidant le cache de l'application mobile.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-comments text-blue-500"></i>
|
||||
<span class="text-600 text-sm">6 messages</span>
|
||||
<i class="pi pi-clock text-600 ml-3"></i>
|
||||
<span class="text-600 text-sm">Résolu en 2 jours</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-1">
|
||||
<i class="pi pi-star-fill text-yellow-400"></i>
|
||||
<span class="text-600 text-sm">Note: 5/5</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ticket 4 - Fermé -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200 opacity-70">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-red-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-times text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#TK-2024-0095 - Demande modification base</h6>
|
||||
<div class="flex align-items-center gap-2 mb-1">
|
||||
<p:tag value="FERMÉ" severity="danger" styleClass="text-xs" />
|
||||
<p:tag value="HAUTE" severity="danger" styleClass="text-xs" />
|
||||
<p:tag value="FONCTIONNALITÉ" severity="help" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-0">Créé le 28 décembre 2023 • Fermé le 5 janvier 2024</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-600 text-sm mb-2">Agent: Marc Durand</div>
|
||||
<p:commandButton value="Rouvrir"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-replay" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-3">
|
||||
Demande de modification des champs de la base de données membres pour ajouter
|
||||
des informations métier spécifiques.
|
||||
</p>
|
||||
<div class="surface-red-50 border-left-3 border-red-500 p-3 mb-3">
|
||||
<p class="text-red-700 text-sm mb-0">
|
||||
<i class="pi pi-times-circle mr-2"></i>
|
||||
<strong>Fermé:</strong> Demande non compatible avec l'architecture actuelle.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-comments text-blue-500"></i>
|
||||
<span class="text-600 text-sm">8 messages</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-ban text-red-500"></i>
|
||||
<span class="text-red-600 text-sm">Non résolu</span>
|
||||
<span class="text-600 text-sm">#{ticket.nbMessages != null ? ticket.nbMessages : 0} message#{ticket.nbMessages != null and ticket.nbMessages > 1 ? 's' : ''}</span>
|
||||
#{ticket.nbFichiers != null and ticket.nbFichiers > 0 ? '<i class="pi pi-paperclip text-600 ml-3"></i><span class="text-600 text-sm">' + ticket.nbFichiers + ' fichier' + (ticket.nbFichiers > 1 ? 's' : '') + '</span>' : ''}
|
||||
</div>
|
||||
#{ticket.noteSatisfaction != null ? '<div class="flex align-items-center gap-1"><i class="pi pi-star-fill text-yellow-400"></i><span class="text-600 text-sm">Note: ' + ticket.noteSatisfaction + '/5</span></div>' : ''}
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
|
||||
<p:dataTable value="#{ticketBean.tickets}"
|
||||
var="ticket"
|
||||
emptyMessage="Aucun ticket trouvé"
|
||||
rendered="#{empty ticketBean.tickets}">
|
||||
<p:column headerText="Numéro">#{ticket.numeroTicket}</p:column>
|
||||
<p:column headerText="Sujet">#{ticket.sujet}</p:column>
|
||||
<p:column headerText="Statut">
|
||||
<p:tag value="#{ticket.statut}"
|
||||
severity="#{ticket.statut == 'RESOLU' ? 'success' : (ticket.statut == 'FERME' ? 'danger' : (ticket.statut == 'EN_ATTENTE' ? 'info' : 'warning'))}" />
|
||||
</p:column>
|
||||
<p:column headerText="Priorité">
|
||||
<p:tag value="#{ticket.priorite}"
|
||||
severity="#{ticket.priorite == 'URGENTE' or ticket.priorite == 'HAUTE' ? 'danger' : (ticket.priorite == 'NORMALE' ? 'success' : 'secondary')}" />
|
||||
</p:column>
|
||||
<p:column headerText="Date Création">#{ticket.dateCreation}</p:column>
|
||||
<p:column headerText="Actions">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Voir détails"
|
||||
action="#{ticketBean.voirDetails}"
|
||||
update="@form">
|
||||
<f:setPropertyActionListener target="#{ticketBean.ticketSelectionne}" value="#{ticket}" />
|
||||
</p:commandButton>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -371,7 +265,8 @@
|
||||
header="Créer un Nouveau Ticket"
|
||||
modal="true"
|
||||
width="800"
|
||||
styleClass="surface-0">
|
||||
styleClass="surface-0"
|
||||
visible="#{ticketBean.afficherDialogNouveauTicket}">
|
||||
<h:form id="nouveauTicketForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
@@ -421,11 +316,14 @@
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('nouveauTicketDialog').hide()"
|
||||
action="#{ticketBean.fermerDialogNouveauTicket}"
|
||||
update="@form"
|
||||
type="button" />
|
||||
<p:commandButton value="Créer le Ticket"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-send" />
|
||||
icon="pi pi-send"
|
||||
action="#{ticketBean.creerTicket}"
|
||||
update="@form" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
|
||||
<p:column headerText="Date" sortBy="#{demande.dateDemande}">
|
||||
<h:outputText value="#{demande.dateDemande}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy"/>
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate"/>
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
|
||||
<p:column headerText="Date" sortBy="#{cotisation.dateCreation}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.dateCreation}" rendered="#{cotisation.dateCreation != null}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" />
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDateTime" />
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{cotisationsGestionBean}"/>
|
||||
<ui:param name="page" value="#{cotisationsBean}"/>
|
||||
<ui:define name="title">Rapports Financiers - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{cotisationsGestionBean}"/>
|
||||
<ui:param name="page" value="#{cotisationsBean}"/>
|
||||
<ui:define name="title">Relances de Cotisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
|
||||
@@ -1,657 +1,275 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:uf="http://xmlns.jcp.org/jsf/composite/components"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui" xmlns:uf="http://xmlns.jcp.org/jsf/composite/components"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{membreListeBean}"/>
|
||||
<ui:define name="title">Liste des Membres - UnionFlow</ui:define>
|
||||
<ui:define name="title">Gestion des Membres</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-blue-500" />
|
||||
<ui:param name="title" value="Liste des Membres" />
|
||||
<ui:param name="description" value="Gestion et suivi des membres de l'association" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsMembres">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouveau membre" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="outcome" value="/pages/secure/membre/inscription" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Import/Export" />
|
||||
<ui:param name="icon" value="pi pi-upload" />
|
||||
<ui:param name="onclick" value="PF('dlgImportExport').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
<h:form id="formMembres">
|
||||
<p:messages id="messages" showDetail="true" closable="true" />
|
||||
|
||||
<!-- ================================================================
|
||||
EN-TÊTE (DRY/WOU: card-header)
|
||||
================================================================ -->
|
||||
<ui:decorate template="/templates/components/cards/card-header.xhtml">
|
||||
<ui:param name="title" value="Gestion des Membres" />
|
||||
<ui:param name="subtitle" value="Liste, recherche et gestion des membres de l'organisation." />
|
||||
<ui:param name="styleClass" value="mb-3" />
|
||||
<ui:define name="actions">
|
||||
<p:button value="Nouveau Membre" icon="pi pi-user-plus" outcome="membreInscriptionPage"
|
||||
styleClass="ui-button-success mr-2" />
|
||||
<p:commandButton value="Import / Export" icon="pi pi-file-excel"
|
||||
onclick="PF('dlgImportExport').show();" type="button" styleClass="ui-button-info" />
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Liste des membres -->
|
||||
<div class="card">
|
||||
<h:form id="formMembres">
|
||||
<h5>Tous les Membres</h5>
|
||||
|
||||
<!-- Filtres et recherche (DRY/WOU: filter-bar avec composants réutilisables) -->
|
||||
<ui:decorate template="/templates/components/cards/filter-bar.xhtml">
|
||||
<ui:param name="title" value="Filtres" />
|
||||
<ui:param name="styleClass" value="mb-3" />
|
||||
<ui:define name="filters">
|
||||
<!-- Recherche globale (DRY/WOU: form-field-search-text avec icône) -->
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchFilter" value="Rechercher" />
|
||||
<span class="p-input-icon-left w-full">
|
||||
<i class="pi pi-search"></i>
|
||||
<p:inputText id="searchFilter"
|
||||
placeholder="Nom, prénom, email..."
|
||||
value="#{membreListeBean.searchFilter}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update="dtMembres" delay="500"/>
|
||||
</p:inputText>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statut (DRY/WOU: form-field-select avec AJAX) -->
|
||||
<div class="col-12 md:col-2">
|
||||
<ui:include src="/templates/components/forms/form-field-select.xhtml">
|
||||
<ui:param name="id" value="statutFilter" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{membreListeBean.statutFilter}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
|
||||
<f:selectItem itemLabel="Suspendu" itemValue="SUSPENDU" />
|
||||
<f:selectItem itemLabel="Radié" itemValue="RADIE" />
|
||||
</ui:define>
|
||||
<ui:define name="ajax">
|
||||
<p:ajax event="change" update="dtMembres" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Type (DRY/WOU: form-field-select avec AJAX) -->
|
||||
<div class="col-12 md:col-2">
|
||||
<ui:include src="/templates/components/forms/form-field-select.xhtml">
|
||||
<ui:param name="id" value="typeFilter" />
|
||||
<ui:param name="label" value="Type" />
|
||||
<ui:param name="value" value="#{membreListeBean.typeFilter}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Associé" itemValue="ASSOCIE" />
|
||||
<f:selectItem itemLabel="Bienfaiteur" itemValue="BIENFAITEUR" />
|
||||
<f:selectItem itemLabel="Honoraire" itemValue="HONORAIRE" />
|
||||
</ui:define>
|
||||
<ui:define name="ajax">
|
||||
<p:ajax event="change" update="dtMembres" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Cotisation (DRY/WOU: form-field-select avec AJAX) -->
|
||||
<div class="col-12 md:col-2">
|
||||
<ui:include src="/templates/components/forms/form-field-select.xhtml">
|
||||
<ui:param name="id" value="cotisationFilter" />
|
||||
<ui:param name="label" value="Cotisation" />
|
||||
<ui:param name="value" value="#{membreListeBean.cotisationFilter}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Toutes cotisations" itemValue="" />
|
||||
<f:selectItem itemLabel="À jour" itemValue="A_JOUR" />
|
||||
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
|
||||
<f:selectItem itemLabel="Jamais payé" itemValue="JAMAIS_PAYE" />
|
||||
</ui:define>
|
||||
<ui:define name="ajax">
|
||||
<p:ajax event="change" update="dtMembres" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Entité/Organisation (DRY/WOU: form-field-select avec AJAX) -->
|
||||
<div class="col-12 md:col-2">
|
||||
<ui:include src="/templates/components/forms/form-field-select.xhtml">
|
||||
<ui:param name="id" value="entiteFilter" />
|
||||
<ui:param name="label" value="Entité" />
|
||||
<ui:param name="value" value="#{membreListeBean.entiteFilter}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Toutes entités" itemValue="" />
|
||||
<f:selectItems value="#{membreListeBean.entitesDisponibles}"
|
||||
var="entite"
|
||||
itemLabel="#{entite.nom}"
|
||||
itemValue="#{entite.id}" />
|
||||
</ui:define>
|
||||
<ui:define name="ajax">
|
||||
<p:ajax event="change" update="dtMembres" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
</ui:define>
|
||||
<ui:define name="actions">
|
||||
<!-- Filtres avancés (DRY/WOU: button-secondary) -->
|
||||
<div class="col-12 md:col-auto">
|
||||
<div class="field">
|
||||
<label class="invisible">Filtres avancés</label>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Filtres avancés" />
|
||||
<ui:param name="icon" value="pi pi-filter" />
|
||||
<ui:param name="onclick" value="PF('dlgFiltresAvances').show();" />
|
||||
<ui:param name="styleClass" value="w-full" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actualiser (DRY/WOU: button-secondary avec icône seule) -->
|
||||
<div class="col-12 md:col-auto">
|
||||
<div class="field">
|
||||
<label class="invisible">Actualiser</label>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{membreListeBean.actualiser}" />
|
||||
<ui:param name="update" value=":formMembres:dtMembres" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="styleClass" value="w-full" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Réinitialiser (DRY/WOU: button-secondary) -->
|
||||
<div class="col-12 md:col-auto">
|
||||
<div class="field">
|
||||
<label class="invisible">Réinitialiser</label>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-filter-slash" />
|
||||
<ui:param name="action" value="#{membreListeBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="dtMembres searchFilter statutFilter typeFilter cotisationFilter entiteFilter" />
|
||||
<ui:param name="styleClass" value="w-full" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
<!-- ================================================================
|
||||
STATISTIQUES (DRY/WOU: stat-card)
|
||||
================================================================ -->
|
||||
<h:panelGroup id="panelStatistiques" layout="block" styleClass="grid mb-3">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:decorate template="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreListeBean.totalMembres}" />
|
||||
<ui:param name="label" value="Total Membres" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="bg-blue-100" />
|
||||
</ui:decorate>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:decorate template="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreListeBean.membresActifs}" />
|
||||
<ui:param name="label" value="Actifs" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="bg-green-100" />
|
||||
</ui:decorate>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:decorate template="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreListeBean.membresInactifs}" />
|
||||
<ui:param name="label" value="Inactifs / Suspendus" />
|
||||
<ui:param name="icon" value="pi pi-ban" />
|
||||
<ui:param name="bgColor" value="bg-orange-100" />
|
||||
</ui:decorate>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:decorate template="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreListeBean.nouveauxMembres}" />
|
||||
<ui:param name="label" value="Nouveaux (30j)" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="bgColor" value="bg-purple-100" />
|
||||
</ui:decorate>
|
||||
</div>
|
||||
</h:panelGroup>
|
||||
|
||||
<!-- DataTable -->
|
||||
<p:dataTable id="dtMembres"
|
||||
var="membre"
|
||||
value="#{membreListeBean.membres}"
|
||||
paginator="true"
|
||||
rows="15"
|
||||
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
|
||||
rowsPerPageTemplate="10,15,25,50"
|
||||
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
|
||||
selection="#{membreListeBean.selectedMembres}"
|
||||
rowKey="#{membre.id}"
|
||||
selectionMode="multiple"
|
||||
styleClass="mt-3">
|
||||
|
||||
<p:column selectionMode="multiple" style="width:50px" />
|
||||
|
||||
<p:column headerText="N° Membre" sortBy="#{membre.numeroMembre}" style="width:120px">
|
||||
<h:outputText value="#{membre.numeroMembre}" styleClass="font-mono font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{membre.nom}">
|
||||
<div class="flex align-items-center">
|
||||
<div class="border-circle overflow-hidden mr-3"
|
||||
style="width: 40px; height: 40px;">
|
||||
<h:graphicImage value="#{membre.photoUrl}"
|
||||
style="width: 100%; height: 100%; object-fit: cover;"
|
||||
rendered="#{membre.photoUrl != null}" />
|
||||
<div class="bg-primary text-white flex align-items-center justify-content-center w-full h-full"
|
||||
rendered="#{membre.photoUrl == null}">
|
||||
<span style="font-size: 0.9rem;">#{membre.initiales}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-medium text-900">#{membre.nomComplet}</div>
|
||||
<div class="text-600 text-sm">
|
||||
<span>#{membre.telephone}</span>
|
||||
<span class="mx-2">•</span>
|
||||
<span>#{membre.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{membre.typeMembre}" style="width:120px">
|
||||
<p:tag value="#{membre.typeMembre}"
|
||||
severity="#{membre.typeSeverity != null ? membre.typeSeverity : 'info'}"
|
||||
icon="pi #{membre.typeIcon != null ? membre.typeIcon : 'pi-user'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{membre.statut}" style="width:100px">
|
||||
<p:tag value="#{membre.statut}"
|
||||
severity="#{membre.statutSeverity}"
|
||||
icon="pi #{membre.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{membre.associationNom}" style="width:150px">
|
||||
<h:outputText value="#{membre.associationNom != null ? membre.associationNom : 'Non renseigné'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Adhésion" sortBy="#{membre.dateAdhesion}" style="width:120px">
|
||||
<div>
|
||||
<div class="font-medium">#{membre.dateAdhesion != null ? membre.dateAdhesion : 'Non renseigné'}</div>
|
||||
<small class="text-600">#{membre.anciennete}</small>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Cotisations" style="width:120px">
|
||||
<div class="text-center">
|
||||
<div class="font-bold #{membre.cotisationColor}">#{membre.cotisationStatut}</div>
|
||||
<small class="text-600">#{membre.dernierPaiement}</small>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Participation" style="width:100px">
|
||||
<div class="text-center">
|
||||
<div class="font-bold text-blue-500">#{membre.tauxParticipation}%</div>
|
||||
<small class="text-600">#{membre.evenementsAnnee} événements</small>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<!-- DRY/WOU: Composite Component action-button-view -->
|
||||
<uf:action-button-view itemId="#{membre.id}"
|
||||
detailPage="/pages/secure/membre/profil.xhtml"
|
||||
iconOnly="true"/>
|
||||
<!-- DRY/WOU: Composite Component action-button-edit-nav -->
|
||||
<uf:action-button-edit-nav itemId="#{membre.id}"
|
||||
editPage="/pages/secure/membre/modifier.xhtml"
|
||||
iconOnly="true"/>
|
||||
<ui:include src="/templates/components/buttons/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-dollar" />
|
||||
<ui:param name="action" value="#{membreListeBean.gererCotisations(membre)}" />
|
||||
<ui:param name="title" value="Cotisations" />
|
||||
<ui:param name="severity" value="success" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-envelope" />
|
||||
<ui:param name="action" value="#{membreListeBean.contacterMembre(membre)}" />
|
||||
<ui:param name="update" value=":formMembres :formContact" />
|
||||
<ui:param name="oncomplete" value="PF('dlgContact').show();" />
|
||||
<ui:param name="title" value="Contacter" />
|
||||
<ui:param name="severity" value="" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-ban" />
|
||||
<ui:param name="action" value="#{membreListeBean.suspendreMembre(membre)}" />
|
||||
<ui:param name="onclick" value="return confirm('Êtes-vous sûr de vouloir suspendre ce membre ?');" />
|
||||
<ui:param name="title" value="Suspendre" />
|
||||
<ui:param name="severity" value="danger" />
|
||||
<ui:param name="rendered" value="#{membre.statut == 'ACTIF'}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{membreListeBean.reactiverMembre(membre)}" />
|
||||
<ui:param name="title" value="Réactiver" />
|
||||
<ui:param name="severity" value="success" />
|
||||
<ui:param name="rendered" value="#{membre.statut == 'SUSPENDU'}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
|
||||
<!-- Actions groupées -->
|
||||
<div class="mt-3 flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-600">#{membreListeBean.selectedMembres.size()} membre(s) sélectionné(s)</span>
|
||||
<span class="text-400 ml-2" rendered="#{empty membreListeBean.selectedMembres}">
|
||||
- Cochez des cases pour activer les actions
|
||||
<!-- ================================================================
|
||||
BARRE DE FILTRES (DRY/WOU: filter-bar)
|
||||
================================================================ -->
|
||||
<ui:decorate template="/templates/components/cards/filter-bar.xhtml">
|
||||
<ui:param name="title" value="" />
|
||||
<ui:define name="filters">
|
||||
<!-- Recherche textuelle -->
|
||||
<div class="col-12 md:col-4">
|
||||
<span class="p-input-icon-left w-full">
|
||||
<i class="pi pi-search" />
|
||||
<p:inputText id="searchFilter" value="#{membreListeBean.searchFilter}"
|
||||
placeholder="Rechercher un membre..." styleClass="w-full">
|
||||
<p:ajax event="keyup" listener="#{membreListeBean.rechercher}" update="dtMembres"
|
||||
delay="500" />
|
||||
</p:inputText>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/buttons/button-info.xhtml">
|
||||
<ui:param name="value" value="Envoyer message" />
|
||||
<ui:param name="icon" value="pi pi-envelope" />
|
||||
<ui:param name="onclick" value="PF('dlgMessageGroupe').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-warning.xhtml">
|
||||
<ui:param name="value" value="Rappel cotisations" />
|
||||
<ui:param name="icon" value="pi pi-bell" />
|
||||
<ui:param name="action" value="#{membreListeBean.rappelCotisationsGroupe}" />
|
||||
<ui:param name="update" value=":formMembres" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Exporter sélection" />
|
||||
<ui:param name="icon" value="pi pi-file-excel" />
|
||||
<ui:param name="action" value="#{membreListeBean.exporterSelection}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Modifier en lot" />
|
||||
<ui:param name="icon" value="pi pi-pencil" />
|
||||
<ui:param name="onclick" value="PF('dlgModificationLot').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Filtres Avancés -->
|
||||
<p:dialog header="Filtres Avancés" widgetVar="dlgFiltresAvances" modal="true" width="600">
|
||||
<h:form id="formFiltresAvances">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMin" value="Âge minimum" />
|
||||
<p:inputNumber id="ageMin" value="#{membreListeBean.ageMin}" symbol="" styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMax" value="Âge maximum" />
|
||||
<p:inputNumber id="ageMax" value="#{membreListeBean.ageMax}" symbol="" styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="genre" value="Genre" />
|
||||
<p:selectOneMenu id="genre" value="#{membreListeBean.genreFilter}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="Homme" itemValue="M" />
|
||||
<f:selectItem itemLabel="Femme" itemValue="F" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="ville" value="Ville" />
|
||||
<p:autoComplete id="ville"
|
||||
value="#{membreListeBean.villeFilter}"
|
||||
completeMethod="#{membreListeBean.completerVilles}"
|
||||
placeholder="Saisir une ville..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateAdhesionDebut" />
|
||||
<ui:param name="label" value="Adhésion après le" />
|
||||
<ui:param name="value" value="#{membreListeBean.dateAdhesionDebut}" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateAdhesionFin" />
|
||||
<ui:param name="label" value="Adhésion avant le" />
|
||||
<ui:param name="value" value="#{membreListeBean.dateAdhesionFin}" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="profession" value="Profession" />
|
||||
<p:autoComplete id="profession"
|
||||
value="#{membreListeBean.professionFilter}"
|
||||
completeMethod="#{membreListeBean.completerProfessions}"
|
||||
placeholder="Saisir une profession..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="desEnfants" value="#{membreListeBean.desEnfants}" />
|
||||
<p:outputLabel for="desEnfants" value=" A des enfants déclarés" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Filtre par statut -->
|
||||
<div class="col-12 md:col-2">
|
||||
<p:selectOneMenu id="statutFilter" value="#{membreListeBean.statutFilter}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
|
||||
<f:selectItem itemLabel="Suspendu" itemValue="SUSPENDU" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<p:ajax event="valueChange" listener="#{membreListeBean.rechercher}" update="dtMembres" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<ui:include src="/templates/components/buttons/button-info.xhtml">
|
||||
<ui:param name="value" value="Appliquer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{membreListeBean.appliquerFiltresAvances}" />
|
||||
<ui:param name="update" value=":formMembres:dtMembres" />
|
||||
<ui:param name="onclick" value="PF('dlgFiltresAvances').hide();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{membreListeBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value=":formFiltresAvances :formMembres:dtMembres" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="onclick" value="PF('dlgFiltresAvances').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="styleClass" value="ui-button-danger" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Message Groupé -->
|
||||
<p:dialog header="Envoyer un Message Groupé" widgetVar="dlgMessageGroupe" modal="true" width="600">
|
||||
<h:form id="formMessageGroupe">
|
||||
<div class="ui-fluid">
|
||||
<ui:include src="/templates/components/forms/form-field-text.xhtml">
|
||||
<ui:param name="id" value="sujetMessage" />
|
||||
<ui:param name="label" value="Sujet" />
|
||||
<ui:param name="value" value="#{membreListeBean.sujetMessage}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Objet du message" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/forms/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="contenuMessage" />
|
||||
<ui:param name="label" value="Message" />
|
||||
<ui:param name="value" value="#{membreListeBean.contenuMessage}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="6" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="canauxMessage" value="Canaux de diffusion" />
|
||||
<p:selectCheckboxMenu id="canauxMessage" value="#{membreListeBean.canauxMessage}"
|
||||
multiple="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="📧 Email" itemValue="EMAIL" />
|
||||
<f:selectItem itemLabel="📱 SMS" itemValue="SMS" />
|
||||
<f:selectItem itemLabel="💬 WhatsApp" itemValue="WHATSAPP" />
|
||||
<f:selectItem itemLabel="🔔 Notification push" itemValue="PUSH" />
|
||||
</p:selectCheckboxMenu>
|
||||
<!-- Filtre par rôle (aligné avec le modèle métier) -->
|
||||
<div class="col-12 md:col-2">
|
||||
<p:selectOneMenu id="roleFilter" value="#{membreListeBean.roleFilter}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les rôles" itemValue="" />
|
||||
<f:selectItem itemLabel="Responsable" itemValue="RESPONSABLE" />
|
||||
<f:selectItem itemLabel="Bureau" itemValue="BUREAU" />
|
||||
<p:ajax event="valueChange" listener="#{membreListeBean.rechercher}" update="dtMembres" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="surface-50 p-3 border-round">
|
||||
<div class="font-medium mb-2">Destinataires :</div>
|
||||
<div class="text-600">#{membreListeBean.selectedMembres.size()} membre(s) recevront ce message</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<ui:include src="/templates/components/buttons/button-info.xhtml">
|
||||
<ui:param name="value" value="Envoyer" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{membreListeBean.envoyerMessageGroupe}" />
|
||||
<ui:param name="update" value=":formMessageGroupe :formMembres" />
|
||||
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="onclick" value="PF('dlgMessageGroupe').hide();" />
|
||||
<ui:param name="outlined" value="false" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Import/Export -->
|
||||
<p:dialog header="Import/Export des Membres" widgetVar="dlgImportExport" modal="true" width="500">
|
||||
<h:form id="formImportExport">
|
||||
<p:tabView>
|
||||
<p:tab title="Import">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="fichierImport" value="Fichier Excel" />
|
||||
<p:fileUpload id="fichierImport" mode="simple" skinSimple="true"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="mettreAJourExistants" value="#{membreListeBean.mettreAJourExistants}" />
|
||||
<p:outputLabel for="mettreAJourExistants" value=" Mettre à jour les membres existants" />
|
||||
</div>
|
||||
|
||||
<div class="surface-50 p-3 border-round">
|
||||
<div class="font-medium mb-2">Format attendu :</div>
|
||||
<small class="text-600">
|
||||
Colonnes : Nom, Prénom, Email, Téléphone, Date naissance, Adresse, Profession, Type membre
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Importer" />
|
||||
<ui:param name="icon" value="pi pi-upload" />
|
||||
<ui:param name="action" value="#{membreListeBean.importerMembres}" />
|
||||
<ui:param name="update" value=":formImportExport :formMembres" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-info.xhtml">
|
||||
<ui:param name="value" value="Télécharger modèle" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="action" value="#{membreListeBean.telechargerModele}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</p:tab>
|
||||
|
||||
<p:tab title="Export">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatExport" value="Format" />
|
||||
<p:selectOneMenu id="formatExport" value="#{membreListeBean.formatExport}">
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="CSV (.csv)" itemValue="CSV" />
|
||||
<f:selectItem itemLabel="PDF (.pdf)" itemValue="PDF" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="colonnesExport" value="Colonnes à exporter" />
|
||||
<p:selectCheckboxMenu id="colonnesExport" value="#{membreListeBean.colonnesExport}"
|
||||
multiple="true">
|
||||
<f:selectItem itemLabel="Informations personnelles" itemValue="PERSO" />
|
||||
<f:selectItem itemLabel="Coordonnées" itemValue="CONTACT" />
|
||||
<f:selectItem itemLabel="Informations adhésion" itemValue="ADHESION" />
|
||||
<f:selectItem itemLabel="Cotisations" itemValue="COTISATIONS" />
|
||||
<f:selectItem itemLabel="Participation événements" itemValue="EVENEMENTS" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="exporterSelection" value="#{membreListeBean.exporterSelection}" />
|
||||
<p:outputLabel for="exporterSelection" value=" Exporter seulement la sélection" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="action" value="#{membreListeBean.exporterMembres}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</p:tab>
|
||||
</p:tabView>
|
||||
|
||||
<div class="flex justify-content-end mt-3">
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Fermer" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="onclick" value="PF('dlgImportExport').hide();" />
|
||||
<ui:param name="outlined" value="false" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Contact Membre -->
|
||||
<h:form id="formContact">
|
||||
<p:dialog id="dlgContact"
|
||||
header="Contacter #{membreListeBean.membreAContacter != null ? membreListeBean.membreAContacter.nomComplet : 'Membre'}"
|
||||
widgetVar="dlgContact"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 600px;"
|
||||
visible="#{membreListeBean.dialogContactVisible}">
|
||||
<div class="ui-fluid" rendered="#{membreListeBean.membreAContacter != null}">
|
||||
<div class="field mb-4">
|
||||
<div class="surface-100 border-round p-3">
|
||||
<div class="flex align-items-center">
|
||||
<div class="w-3rem h-3rem border-circle bg-primary-100 flex align-items-center justify-content-center mr-3">
|
||||
<i class="pi pi-user text-primary text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-semibold text-900">#{membreListeBean.membreAContacter.nomComplet}</div>
|
||||
<div class="text-600 text-sm">#{membreListeBean.membreAContacter.email != null ? membreListeBean.membreAContacter.email : 'Email non renseigné'}</div>
|
||||
<div class="text-600 text-sm">#{membreListeBean.membreAContacter.telephone != null ? membreListeBean.membreAContacter.telephone : 'Téléphone non renseigné'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Filtre par organisation -->
|
||||
<div class="col-12 md:col-2">
|
||||
<p:selectOneMenu id="entiteFilter" value="#{membreListeBean.entiteFilter}" styleClass="w-full"
|
||||
filter="true" filterMatchMode="contains">
|
||||
<f:selectItem itemLabel="Toutes les organisations" itemValue="" />
|
||||
<f:selectItems value="#{membreListeBean.organisationsDisponibles}" var="org"
|
||||
itemLabel="#{org.nom}" itemValue="#{org.id}" />
|
||||
<p:ajax event="valueChange" listener="#{membreListeBean.rechercher}" update="dtMembres" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<ui:include src="/templates/components/forms/form-field-text.xhtml">
|
||||
<ui:param name="id" value="sujetContact" />
|
||||
<ui:param name="label" value="Sujet" />
|
||||
<ui:param name="value" value="#{membreListeBean.sujetContact}" />
|
||||
<ui:param name="placeholder" value="Sujet du message (optionnel)" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<ui:include src="/templates/components/forms/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="messageContact" />
|
||||
<ui:param name="label" value="Message *" />
|
||||
<ui:param name="value" value="#{membreListeBean.messageContact}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="6" />
|
||||
<ui:param name="placeholder" value="Saisissez votre message..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{membreListeBean.annulerContact}" />
|
||||
<ui:param name="update" value=":formContact" />
|
||||
<ui:param name="oncomplete" value="PF('dlgContact').hide();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/buttons/button-success.xhtml">
|
||||
<ui:param name="value" value="Envoyer" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{membreListeBean.envoyerMessageContact}" />
|
||||
<ui:param name="update" value=":formContact :formMembres" />
|
||||
<ui:param name="oncomplete" value="if(!args.validationFailed) { PF('dlgContact').hide(); }" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
<ui:define name="actions">
|
||||
<p:commandButton icon="pi pi-filter" title="Filtres avancés"
|
||||
onclick="PF('dlgFiltresAvances').show();" type="button" styleClass="ui-button-outlined mr-1" />
|
||||
<p:commandButton icon="pi pi-refresh" title="Actualiser" action="#{membreListeBean.actualiser}"
|
||||
update="dtMembres panelStatistiques messages" styleClass="ui-button-outlined" />
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<!-- ================================================================
|
||||
ACTIONS GROUPÉES (visible si sélection)
|
||||
================================================================ -->
|
||||
<h:panelGroup id="panelActionsGroupeesWrapper">
|
||||
<h:panelGroup id="panelActionsGroupees" layout="block" styleClass="flex gap-2 mb-3"
|
||||
rendered="#{not empty membreListeBean.selectedMembres}">
|
||||
<p:commandButton value="Rappel Cotisations" icon="pi pi-bell"
|
||||
action="#{membreListeBean.rappelCotisationsGroupe}" update="messages"
|
||||
styleClass="ui-button-warning ui-button-sm" />
|
||||
<p:commandButton value="Message Groupé" icon="pi pi-envelope"
|
||||
onclick="PF('dlgMessageGroupe').show();" type="button"
|
||||
styleClass="ui-button-info ui-button-sm" />
|
||||
<p:commandButton value="Exporter Sélection" icon="pi pi-download" ajax="false"
|
||||
action="#{membreListeBean.exporterSelection}" styleClass="ui-button-secondary ui-button-sm" />
|
||||
<h:outputText value="#{membreListeBean.selectedMembres.size()} membre(s) sélectionné(s)"
|
||||
styleClass="ml-2 text-500 align-self-center" />
|
||||
</h:panelGroup>
|
||||
</h:panelGroup>
|
||||
|
||||
<!-- ================================================================
|
||||
DataTable LAZY (pagination/tri/filtrage côté serveur)
|
||||
================================================================ -->
|
||||
<p:dataTable id="dtMembres" var="membre" value="#{membreListeBean.lazyModel}" lazy="true" paginator="true"
|
||||
rows="20" rowsPerPageTemplate="10,20,50"
|
||||
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
|
||||
currentPageReportTemplate="{startRecord}-{endRecord} sur {totalRecords}"
|
||||
selection="#{membreListeBean.selectedMembres}" rowKey="#{membre.id}" emptyMessage="Aucun membre trouvé."
|
||||
stripedRows="true" showGridlines="false" size="small" styleClass="mb-4" tableStyle="min-width: 60rem">
|
||||
|
||||
<!-- AJAX sélection pour mise à jour des actions groupées -->
|
||||
<p:ajax event="rowSelect" update=":formMembres:panelActionsGroupeesWrapper" />
|
||||
<p:ajax event="rowUnselect" update=":formMembres:panelActionsGroupeesWrapper" />
|
||||
<p:ajax event="toggleSelect" update=":formMembres:panelActionsGroupeesWrapper" />
|
||||
|
||||
<!-- Colonne sélection checkbox -->
|
||||
<p:column selectionMode="multiple" headerText="" style="width: 3rem; text-align: center;" />
|
||||
|
||||
<!-- Colonne: Membre (Nom + Email) -->
|
||||
<ui:decorate template="/templates/components/columns/column-name-with-subtitle.xhtml">
|
||||
<ui:param name="headerText" value="Membre" />
|
||||
<ui:param name="name" value="#{membre.nomComplet}" />
|
||||
<ui:param name="subtitle" value="#{membre.email}" />
|
||||
<ui:param name="sortBy" value="#{membre.nom}" />
|
||||
<ui:param name="filterBy" value="#{membre.nom}" />
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Colonne: Rôle -->
|
||||
<ui:decorate template="/templates/components/columns/column-tag.xhtml">
|
||||
<ui:param name="headerText" value="Rôle" />
|
||||
<ui:param name="value" value="#{membre.typeMembre}" />
|
||||
<ui:param name="severity" value="#{membre.typeSeverity}" />
|
||||
<ui:param name="icon" value="#{membre.typeIcon}" />
|
||||
<ui:param name="width" value="8rem" />
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Colonne: Organisation -->
|
||||
<ui:decorate template="/templates/components/columns/column-text-with-icon.xhtml">
|
||||
<ui:param name="headerText" value="Organisation" />
|
||||
<ui:param name="icon" value="pi pi-building" />
|
||||
<ui:param name="text" value="#{not empty membre.associationNom ? membre.associationNom : '—'}" />
|
||||
<ui:param name="sortBy" value="#{membre.associationNom}" />
|
||||
<ui:param name="filterBy" value="#{membre.associationNom}" />
|
||||
<ui:param name="styleClass" value="#{empty membre.associationNom ? 'text-500' : ''}" />
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Colonne: Téléphone -->
|
||||
<ui:decorate template="/templates/components/columns/column-text-with-icon.xhtml">
|
||||
<ui:param name="headerText" value="Téléphone" />
|
||||
<ui:param name="icon" value="pi pi-phone" />
|
||||
<ui:param name="text" value="#{not empty membre.telephone ? membre.telephone : '—'}" />
|
||||
<ui:param name="styleClass" value="#{empty membre.telephone ? 'text-500' : ''}" />
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Colonne: Statut -->
|
||||
<ui:decorate template="/templates/components/columns/column-tag.xhtml">
|
||||
<ui:param name="headerText" value="Statut" />
|
||||
<ui:param name="value" value="#{membre.statutLibelle}" />
|
||||
<ui:param name="severity" value="#{membre.statutSeverity}" />
|
||||
<ui:param name="icon" value="#{membre.statutIcon}" />
|
||||
<ui:param name="sortBy" value="#{membre.statut}" />
|
||||
<ui:param name="width" value="8rem" />
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Colonne: Date Adhésion -->
|
||||
<p:column headerText="Adhésion" sortBy="#{membre.dateAdhesion}"
|
||||
style="width: 8rem; text-align: center;">
|
||||
<i class="pi pi-calendar mr-1 text-primary"></i>
|
||||
<h:outputText value="#{membre.dateAdhesion}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne: Actions (DRY/WOU: column-actions) -->
|
||||
<ui:decorate template="/templates/components/columns/column-actions.xhtml">
|
||||
<ui:param name="width" value="14rem" />
|
||||
<ui:define name="actions">
|
||||
<!-- Voir le profil -->
|
||||
<p:button icon="pi pi-user" outcome="membreProfilPage" title="Profil"
|
||||
styleClass="ui-button-info ui-button-sm ui-button-rounded mr-1">
|
||||
<f:param name="id" value="#{membre.id}" />
|
||||
</p:button>
|
||||
|
||||
<!-- Éditer -->
|
||||
<p:button icon="pi pi-pencil" outcome="membreModifierPage" title="Modifier"
|
||||
styleClass="ui-button-warning ui-button-sm ui-button-rounded mr-1">
|
||||
<f:param name="id" value="#{membre.id}" />
|
||||
</p:button>
|
||||
|
||||
<!-- Contacter -->
|
||||
<p:commandButton icon="pi pi-envelope" title="Contacter"
|
||||
action="#{membreListeBean.contacterMembre(membre)}" process="@this"
|
||||
oncomplete="PF('dlgContact').show();" update=":dlgContact"
|
||||
styleClass="ui-button-help ui-button-sm ui-button-rounded mr-1" />
|
||||
|
||||
<!-- Suspendre (visible si actif) -->
|
||||
<p:commandButton icon="pi pi-ban" title="Suspendre"
|
||||
action="#{membreListeBean.suspendreMembre(membre)}"
|
||||
update="dtMembres messages panelStatistiques" rendered="#{membre.statut == 'ACTIF'}"
|
||||
styleClass="ui-button-danger ui-button-sm ui-button-rounded mr-1">
|
||||
<p:confirm header="Confirmation" message="Suspendre #{membre.nomComplet} ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
|
||||
<!-- Réactiver (visible si suspendu) -->
|
||||
<p:commandButton icon="pi pi-replay" title="Réactiver"
|
||||
action="#{membreListeBean.reactiverMembre(membre)}"
|
||||
update="dtMembres messages panelStatistiques" rendered="#{membre.statut == 'SUSPENDU'}"
|
||||
styleClass="ui-button-success ui-button-sm ui-button-rounded" />
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</p:dataTable>
|
||||
|
||||
<!-- Confirmation dialog global -->
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" responsive="true" width="450">
|
||||
<p:commandButton value="Oui" type="button" styleClass="ui-button-danger ui-confirmdialog-yes"
|
||||
icon="pi pi-check" />
|
||||
<p:commandButton value="Non" type="button" styleClass="ui-button-secondary ui-confirmdialog-no"
|
||||
icon="pi pi-times" />
|
||||
</p:confirmDialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
<!-- ================================================================
|
||||
DIALOGS EXTRAITS (DRY/WOU: fichiers include séparés)
|
||||
================================================================ -->
|
||||
<ui:include src="/ui/includes/membre-dialog-filtres-avances.xhtml" />
|
||||
<ui:include src="/ui/includes/membre-dialog-message-groupe.xhtml" />
|
||||
<ui:include src="/ui/includes/membre-dialog-import-export.xhtml" />
|
||||
<ui:include src="/ui/includes/membre-dialog-contact.xhtml" />
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,122 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:uf="http://xmlns.jcp.org/jsf/composite/components">
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Organisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:composition template="/templates/main-template.xhtml">
|
||||
<ui:param name="page" value="#{organisationsBean}"/>
|
||||
<ui:define name="title">Gestion des Organisations</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:form id="formOrganisations">
|
||||
<p:messages id="messages" showDetail="true" closable="true"/>
|
||||
|
||||
<!-- En-tête avec titre et action principale (DRY/WOU: card-header) -->
|
||||
<ui:decorate template="/templates/components/cards/card-header.xhtml">
|
||||
<ui:param name="title" value="Gestion des Organisations" />
|
||||
<ui:param name="subtitle" value="Liste complète des organisations avec filtres et actions." />
|
||||
<ui:param name="styleClass" value="mb-3" />
|
||||
<ui:define name="actions">
|
||||
<p:button value="Nouvelle Organisation"
|
||||
icon="pi pi-plus"
|
||||
outcome="/pages/secure/organisation/nouvelle"
|
||||
styleClass="ui-button-success" />
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
<div class="ui-fluid">
|
||||
|
||||
<!-- Statistiques (DRY/WOU: stat-card) -->
|
||||
<div class="grid mb-3">
|
||||
<ui:include src="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.totalOrganisations}" />
|
||||
<ui:param name="label" value="Total" />
|
||||
<ui:param name="icon" value="pi pi-building" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsActives}" />
|
||||
<ui:param name="label" value="Actives" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsInactives}" />
|
||||
<ui:param name="label" value="Inactives" />
|
||||
<ui:param name="icon" value="pi pi-times-circle" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Filtres et recherche (DRY/WOU: filter-bar) -->
|
||||
<ui:decorate template="/templates/components/cards/filter-bar.xhtml">
|
||||
<ui:param name="title" value="Filtres" />
|
||||
<ui:param name="styleClass" value="mb-3" />
|
||||
<ui:define name="filters">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="rechercheGlobale" value="Rechercher" />
|
||||
<p:inputText id="rechercheGlobale"
|
||||
value="#{organisationsBean.rechercheGlobale}"
|
||||
placeholder="Nom, ville, description..."
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}" delay="500"/>
|
||||
</p:inputText>
|
||||
</div>
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- EN-TÊTE -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<div class="card mb-3">
|
||||
<div class="formgrid grid align-items-center">
|
||||
<div class="field col-12 lg:col-8 mb-0">
|
||||
<h2 class="text-primary font-bold mb-1 mt-0">
|
||||
<i class="pi pi-building text-blue-500 mr-2"></i>
|
||||
Organisations
|
||||
</h2>
|
||||
<p class="text-600 m-0">
|
||||
Administration des organisations ·
|
||||
<span class="font-semibold text-900">#{organisationsBean.totalOrganisations}</span> au total ·
|
||||
<span class="font-semibold text-green-600">#{organisationsBean.organisationsActives} active(s)</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<p:outputLabel for="filtreStatut" value="Statut" />
|
||||
<p:selectOneMenu id="filtreStatut"
|
||||
value="#{organisationsBean.filtreStatut}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.statutsSelectItems}" />
|
||||
<p:ajax event="change" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}"/>
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<p:outputLabel for="filtreType" value="Type" />
|
||||
<p:selectOneMenu id="filtreType"
|
||||
value="#{organisationsBean.filtreType}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.typesSelectItems}" />
|
||||
<p:ajax event="change" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}"/>
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
<ui:define name="actions">
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<label class="invisible">Actions</label>
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-filter-slash"
|
||||
action="#{organisationsBean.reinitialiserFiltres}"
|
||||
update="dtOrganisations rechercheGlobale filtreStatut filtreType"
|
||||
styleClass="ui-button-secondary w-full" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<label class="invisible">Actions</label>
|
||||
<div class="field col-12 lg:col-4 mb-0 flex justify-content-end gap-2">
|
||||
<h:form id="formEntete">
|
||||
<p:commandButton value="Rafraîchir"
|
||||
icon="pi pi-refresh"
|
||||
action="#{organisationsBean.recharger}"
|
||||
update="@form"
|
||||
styleClass="ui-button-secondary w-full" />
|
||||
styleClass="ui-button-secondary ui-button-outlined"
|
||||
actionListener="#{organisationsBean.recharger}"
|
||||
update=":panelKPIs :formOrganisations" />
|
||||
</h:form>
|
||||
<p:button value="Nouvelle organisation"
|
||||
icon="pi pi-plus"
|
||||
styleClass="ui-button-success"
|
||||
outcome="/pages/secure/organisation/nouvelle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- KPIs -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<h:panelGroup id="panelKPIs" layout="block">
|
||||
<div class="formgrid grid">
|
||||
<ui:include src="/templates/components/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Total Organisations" />
|
||||
<ui:param name="value" value="#{organisationsBean.totalOrganisations}" />
|
||||
<ui:param name="icon" value="pi-building" />
|
||||
<ui:param name="iconColor" value="blue-600" />
|
||||
<ui:param name="showGrowth" value="false" />
|
||||
<ui:param name="showProgress" value="false" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Actives" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsActives}" />
|
||||
<ui:param name="icon" value="pi-check-circle" />
|
||||
<ui:param name="iconColor" value="green-600" />
|
||||
<ui:param name="progressValue" value="#{organisationsBean.tauxActivite}" />
|
||||
<ui:param name="noDataLabel" value="Aucune organisation active" />
|
||||
<ui:param name="showGrowth" value="false" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Inactives / Suspendues" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsInactives}" />
|
||||
<ui:param name="icon" value="pi-pause-circle" />
|
||||
<ui:param name="iconColor" value="orange-600" />
|
||||
<ui:param name="showGrowth" value="false" />
|
||||
<ui:param name="showProgress" value="false" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Taux d'activité" />
|
||||
<ui:param name="value" value="#{organisationsBean.tauxActivite} %" />
|
||||
<ui:param name="icon" value="pi-chart-pie" />
|
||||
<ui:param name="iconColor" value="purple-600" />
|
||||
<ui:param name="progressValue" value="#{organisationsBean.tauxActivite}" />
|
||||
<ui:param name="showGrowth" value="false" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:panelGroup>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- FILTRES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<div class="card mb-3">
|
||||
<h5 class="mb-3 mt-0">
|
||||
<i class="pi pi-filter text-blue-500 mr-2"></i>
|
||||
Filtres et Recherche
|
||||
</h5>
|
||||
<h:form id="formFiltres">
|
||||
<div class="formgrid grid align-items-end">
|
||||
<div class="field col-12 md:col-6 lg:col-4">
|
||||
<label for="searchNom" class="block text-900 font-medium mb-2">Nom / Description</label>
|
||||
<span class="p-input-icon-left w-full">
|
||||
<i class="pi pi-search"></i>
|
||||
<p:inputText id="searchNom"
|
||||
value="#{organisationsBean.rechercheGlobale}"
|
||||
placeholder="Nom, ville, description..."
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" delay="400"
|
||||
listener="#{organisationsBean.appliquerFiltres}"
|
||||
update=":formOrganisations:dtOrganisations" />
|
||||
</p:inputText>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<label for="filterStatut" class="block text-900 font-medium mb-2">Statut</label>
|
||||
<p:selectOneMenu id="filterStatut"
|
||||
value="#{organisationsBean.filtreStatut}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.statutsSelectItems}" />
|
||||
<p:ajax listener="#{organisationsBean.appliquerFiltres}"
|
||||
update=":formOrganisations:dtOrganisations" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-3">
|
||||
<label for="filterType" class="block text-900 font-medium mb-2">Type</label>
|
||||
<p:selectOneMenu id="filterType"
|
||||
value="#{organisationsBean.filtreType}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.typesSelectItems}" />
|
||||
<p:ajax listener="#{organisationsBean.appliquerFiltres}"
|
||||
update=":formOrganisations:dtOrganisations" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6 lg:col-2">
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-filter-slash"
|
||||
styleClass="ui-button-secondary ui-button-outlined w-full"
|
||||
actionListener="#{organisationsBean.reinitialiserFiltres}"
|
||||
update="@form :formOrganisations:dtOrganisations" />
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- TABLE -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<div class="card">
|
||||
<h:form id="formOrganisations">
|
||||
<p:messages id="messages" showDetail="true" closable="true" styleClass="mb-3" />
|
||||
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<h5 class="m-0">
|
||||
<i class="pi pi-list text-primary mr-2"></i>
|
||||
Liste des Organisations
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<!-- Table des organisations (DRY/WOU: card-simple) -->
|
||||
<ui:decorate template="/templates/components/cards/card-simple.xhtml">
|
||||
<ui:param name="title" value="Liste des Organisations" />
|
||||
<ui:define name="content">
|
||||
<!-- Note: p:dataTable avec var, sortBy, filterBy doit être directement dans la page -->
|
||||
<p:dataTable id="dtOrganisations"
|
||||
value="#{organisationsBean.organisationsFiltrees}"
|
||||
var="org"
|
||||
@@ -124,97 +166,130 @@
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
paginatorPosition="bottom"
|
||||
emptyMessage="Aucune organisation trouvée"
|
||||
styleClass="table-responsive"
|
||||
size="small">
|
||||
|
||||
<!-- Logo (DRY/WOU: organisation-logo) -->
|
||||
<p:column headerText="" style="width: 80px;">
|
||||
<ui:include src="/templates/components/layout/organisation-logo.xhtml">
|
||||
<ui:param name="logo" value="#{org.logo}"/>
|
||||
<ui:param name="size" value="40"/>
|
||||
</ui:include>
|
||||
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
|
||||
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords} organisations"
|
||||
styleClass="p-datatable-sm p-datatable-gridlines p-datatable-striped"
|
||||
emptyMessage="Aucune organisation trouvée">
|
||||
|
||||
<!-- Organisation : nom + type -->
|
||||
<p:column headerText="Organisation" sortBy="#{org.nom}">
|
||||
<div class="flex align-items-center">
|
||||
<div class="flex align-items-center justify-content-center bg-primary-100 border-circle mr-3"
|
||||
style="width: 2.5rem; height: 2.5rem; min-width: 2.5rem;">
|
||||
<i class="pi pi-building text-primary-600"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-900 font-semibold">#{org.nom}</div>
|
||||
<div class="text-500 text-xs">
|
||||
#{empty org.nomCourt ? '' : org.nomCourt}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Nom avec sous-titre -->
|
||||
<p:column headerText="Nom" sortBy="#{org.nom}" filterBy="#{org.nom}">
|
||||
<h:outputText value="#{org.nom}" styleClass="font-bold"/>
|
||||
<br/>
|
||||
<h:outputText value="#{org.typeLibelle}" styleClass="text-sm text-500"/>
|
||||
</p:column>
|
||||
|
||||
|
||||
<!-- Type -->
|
||||
<p:column headerText="Type" sortBy="#{org.typeAssociation}" style="width: 150px;">
|
||||
<p:tag value="#{org.typeLibelle}"
|
||||
severity="#{org.typeAssociation == 'LIONS_CLUB' ? 'info' : 'primary'}"/>
|
||||
<p:column headerText="Type" sortBy="#{org.typeAssociation}" style="width: 11rem;">
|
||||
<p:tag value="#{org.typeLibelle}"
|
||||
severity="info"
|
||||
styleClass="text-xs" />
|
||||
</p:column>
|
||||
|
||||
|
||||
<!-- Localisation -->
|
||||
<p:column headerText="Localisation" style="width: 200px;">
|
||||
<i class="pi pi-map-marker mr-2 text-500"/>
|
||||
<h:outputText value="#{org.ville}, #{org.region}"/>
|
||||
<p:column headerText="Localisation" style="width: 13rem;">
|
||||
<div class="flex align-items-center text-700 text-sm">
|
||||
<i class="pi pi-map-marker text-400 mr-1"></i>
|
||||
<span>
|
||||
#{empty org.ville ? '' : org.ville}#{(not empty org.ville and not empty org.region) ? ', ' : ''}#{empty org.region ? '' : org.region}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-400 text-xs mt-1" rendered="#{not empty org.pays}">
|
||||
#{org.pays}
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
|
||||
<!-- Membres -->
|
||||
<p:column headerText="Membres" styleClass="text-center" style="width: 100px;">
|
||||
<p:tag value="#{org.nombreMembres}" severity="info" icon="pi pi-users"/>
|
||||
<p:column headerText="Membres" style="width: 7rem; text-align: center;">
|
||||
<div class="text-center">
|
||||
<span class="text-900 font-bold text-lg">
|
||||
#{empty org.nombreMembres ? 0 : org.nombreMembres}
|
||||
</span>
|
||||
<div class="text-500 text-xs">membres</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
|
||||
<!-- Statut -->
|
||||
<p:column headerText="Statut" sortBy="#{org.statut}" styleClass="text-center" style="width: 100px;">
|
||||
<p:tag value="#{org.statut}"
|
||||
severity="#{org.statut == organisationsBean.statutActive ? 'success' : 'warning'}"
|
||||
icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-check' : 'pi pi-times'}"/>
|
||||
<p:column headerText="Statut" sortBy="#{org.statut}" style="width: 9rem; text-align: center;">
|
||||
<p:tag value="#{org.statut}"
|
||||
severity="#{org.statut == organisationsBean.statutActive ? 'success' :
|
||||
(org.statut == organisationsBean.statutSuspendue ? 'danger' :
|
||||
(org.statut == organisationsBean.statutDissoute ? 'danger' : 'warning'))}"
|
||||
icon="pi #{org.statut == organisationsBean.statutActive ? 'pi-check' :
|
||||
(org.statut == organisationsBean.statutSuspendue ? 'pi-ban' : 'pi-pause')}"
|
||||
styleClass="text-xs w-full" />
|
||||
</p:column>
|
||||
|
||||
<!-- Actions (DRY/WOU: Composite Components) -->
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
|
||||
<!-- Actions -->
|
||||
<p:column headerText="Actions" style="width: 10rem;" exportable="false">
|
||||
<div class="flex gap-1">
|
||||
<!-- DRY/WOU: Composite Component action-button-view -->
|
||||
<uf:action-button-view itemId="#{org.id.toString()}"
|
||||
detailPage="/pages/secure/organisation/detail.xhtml"
|
||||
iconOnly="true"/>
|
||||
<!-- DRY/WOU: button-icon pour Modifier -->
|
||||
<p:button icon="pi pi-eye"
|
||||
title="Voir le détail"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
|
||||
href="/pages/secure/organisation/detail.xhtml?id=#{org.id}" />
|
||||
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
actionListener="#{organisationsBean.setOrganisationSelectionnee(org)}"
|
||||
oncomplete="PF('dlgModifier').show();"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
|
||||
title="Modifier"
|
||||
update=":formModifier"
|
||||
styleClass="ui-button-rounded ui-button-warning"
|
||||
title="Modifier"/>
|
||||
<!-- DRY/WOU: button-icon pour Activer/Désactiver -->
|
||||
<p:commandButton icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-ban' : 'pi pi-check'}"
|
||||
actionListener="#{organisationsBean.basculerStatutOrganisation(org)}"
|
||||
update=":formOrganisations:dtOrganisations :formOrganisations:messages"
|
||||
styleClass="ui-button-rounded #{org.statut == organisationsBean.statutActive ? 'ui-button-secondary' : 'ui-button-success'}"
|
||||
title="#{org.statut == organisationsBean.statutActive ? 'Désactiver' : 'Activer'}">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Êtes-vous sûr de vouloir changer le statut de cette organisation ?"
|
||||
icon="pi pi-exclamation-triangle"/>
|
||||
oncomplete="PF('dlgModifier').show();">
|
||||
<f:setPropertyActionListener target="#{organisationsBean.organisationSelectionnee}" value="#{org}" />
|
||||
</p:commandButton>
|
||||
<!-- DRY/WOU: button-icon pour Supprimer -->
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
actionListener="#{organisationsBean.supprimerOrganisation(org)}"
|
||||
update=":formOrganisations:dtOrganisations :formOrganisations:messages"
|
||||
styleClass="ui-button-rounded ui-button-danger"
|
||||
title="Supprimer">
|
||||
|
||||
<p:commandButton icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-ban' : 'pi pi-check'}"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-sm #{org.statut == organisationsBean.statutActive ? 'ui-button-secondary' : 'ui-button-success'}"
|
||||
title="#{org.statut == organisationsBean.statutActive ? 'Désactiver' : 'Activer'}"
|
||||
actionListener="#{organisationsBean.basculerStatutOrganisation(org)}"
|
||||
update=":panelKPIs :formOrganisations:dtOrganisations :formOrganisations:messages">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Êtes-vous sûr de vouloir supprimer cette organisation ? Cette action est irréversible."
|
||||
icon="pi pi-exclamation-triangle"/>
|
||||
message="Changer le statut de cette organisation ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-danger ui-button-sm"
|
||||
title="Supprimer"
|
||||
actionListener="#{organisationsBean.supprimerOrganisation(org)}"
|
||||
update=":panelKPIs :formOrganisations:dtOrganisations :formOrganisations:messages">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Supprimer définitivement cette organisation ? Cette action est irréversible."
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Dialogue de confirmation global (DRY/WOU: confirm-dialog) -->
|
||||
<ui:include src="/templates/components/dialogs/confirm-dialog.xhtml" />
|
||||
</h:form>
|
||||
|
||||
<!-- Dialogue Modifier Organisation (DRY/WOU: form-dialog) -->
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" responsive="true" width="380">
|
||||
<p:commandButton value="Non"
|
||||
type="button"
|
||||
styleClass="ui-button-secondary ui-button-outlined"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('confirmDialog').hide()" />
|
||||
<p:commandButton value="Oui"
|
||||
type="button"
|
||||
styleClass="ui-button-danger"
|
||||
icon="pi pi-check" />
|
||||
</p:confirmDialog>
|
||||
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
</div><!-- /ui-fluid -->
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- DIALOGUE MODIFICATION -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<ui:decorate template="/templates/components/dialogs/form-dialog.xhtml">
|
||||
<ui:param name="dialogId" value="dlgModifier" />
|
||||
<ui:param name="header" value="Modifier Organisation" />
|
||||
<ui:param name="header" value="Modifier l'organisation" />
|
||||
<ui:param name="widgetVar" value="dlgModifier" />
|
||||
<ui:param name="formId" value="formModifier" />
|
||||
<ui:param name="width" value="900" />
|
||||
@@ -225,27 +300,24 @@
|
||||
<ui:include src="/ui/includes/organisation-form.xhtml">
|
||||
<ui:param name="model" value="#{organisationsBean.organisationSelectionnee}" />
|
||||
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
<ui:param name="completionBean" value="#{organisationsBean}" />
|
||||
</ui:include>
|
||||
</ui:fragment>
|
||||
</ui:define>
|
||||
<ui:define name="footer">
|
||||
<!-- Bouton Annuler : type="button" pour éviter la soumission -->
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
type="button"
|
||||
onclick="PF('dlgModifier').hide();"
|
||||
styleClass="ui-button-secondary" />
|
||||
<!-- DRY/WOU: button-form-submit pour action backend -->
|
||||
<ui:decorate template="/templates/components/buttons/button-form-submit.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{organisationsBean.modifierOrganisation}" />
|
||||
<ui:param name="update" value=":formOrganisations:dtOrganisations :formOrganisations:messages" />
|
||||
<ui:param name="oncomplete" value="if(!args.validationFailed) PF('dlgModifier').hide();" />
|
||||
<ui:param name="severity" value="success" />
|
||||
</ui:decorate>
|
||||
styleClass="ui-button-secondary ui-button-outlined" />
|
||||
<p:commandButton value="Enregistrer"
|
||||
icon="pi pi-check"
|
||||
actionListener="#{organisationsBean.modifierOrganisation}"
|
||||
update=":panelKPIs :formOrganisations:dtOrganisations :formOrganisations:messages"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgModifier').hide();"
|
||||
styleClass="ui-button-success" />
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
</html>
|
||||
|
||||
@@ -1,64 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:composition template="/templates/main-template.xhtml">
|
||||
<ui:param name="page" value="#{organisationsBean}"/>
|
||||
<ui:define name="title">Nouvelle Organisation</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- Initialiser le modèle et le catalogue des types à chaque affichage de la vue -->
|
||||
<f:event type="preRenderView" listener="#{organisationsBean.preparerNouvelleOrganisation}" />
|
||||
|
||||
<h:form id="formNouvelleOrganisation">
|
||||
<p:messages id="messages" showDetail="true" closable="true"/>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="flex justify-content-between align-items-center flex-column md:flex-row">
|
||||
<div class="mb-2 md:mb-0">
|
||||
<h3 class="m-0">Nouvelle Organisation</h3>
|
||||
<span class="text-600">
|
||||
Renseignez l'ensemble des informations de l'organisation.
|
||||
</span>
|
||||
<!-- En-tête avec titre et actions (DRY/WOU: card-header) -->
|
||||
<ui:decorate template="/templates/components/cards/card-header.xhtml">
|
||||
<ui:param name="title" value="Nouvelle Organisation" />
|
||||
<ui:param name="subtitle" value="Créez une nouvelle organisation en renseignant les informations essentielles." />
|
||||
<ui:param name="icon" value="pi pi-building" />
|
||||
<ui:param name="styleClass" value="mb-3" />
|
||||
<ui:define name="actions">
|
||||
<!-- Bouton Enregistrer (MethodExpression direct) -->
|
||||
<p:commandButton value="Enregistrer"
|
||||
icon="pi pi-save"
|
||||
action="#{organisationsBean.creerOrganisation}"
|
||||
update="formNouvelleOrganisation messages"
|
||||
styleClass="p-button-success p-button-lg"
|
||||
validateClient="true">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Voulez-vous créer cette organisation ?"
|
||||
icon="pi pi-question-circle"/>
|
||||
</p:commandButton>
|
||||
|
||||
<!-- DRY/WOU: button-secondary pour Annuler -->
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler"/>
|
||||
<ui:param name="icon" value="pi pi-times"/>
|
||||
<ui:param name="outcome" value="/pages/secure/organisation/liste"/>
|
||||
</ui:include>
|
||||
</ui:define>
|
||||
<ui:define name="info">
|
||||
<p class="text-500 text-sm m-0">
|
||||
<i class="pi pi-asterisk text-red-500 mr-1" style="font-size: 0.5rem;"/>
|
||||
Les champs marqués d'un astérisque sont obligatoires
|
||||
</p>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Messages globaux -->
|
||||
<p:messages id="messages" showDetail="true" closable="true" styleClass="mb-3"/>
|
||||
|
||||
<!-- Formulaire (DRY/WOU: card-simple) -->
|
||||
<ui:decorate template="/templates/components/cards/card-simple.xhtml">
|
||||
<ui:param name="styleClass" value="shadow-2" />
|
||||
<ui:define name="content">
|
||||
<!-- DRY/WOU: organisation-form.xhtml include réutilisable -->
|
||||
<ui:include src="/ui/includes/organisation-form.xhtml">
|
||||
<ui:param name="model" value="#{organisationsBean.nouvelleOrganisation}" />
|
||||
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
<ui:param name="completionBean" value="#{organisationsBean}" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Actions du formulaire (bas de page) -->
|
||||
<p:divider styleClass="mt-5"/>
|
||||
|
||||
<div class="flex justify-content-between align-items-center flex-column md:flex-row gap-3 mt-4">
|
||||
<div class="text-600">
|
||||
<i class="pi pi-shield mr-2"/>
|
||||
Toutes les données sont sécurisées et conformes
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<!-- Bouton Réinitialiser avec confirmation -->
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
action="#{organisationsBean.preparerNouvelleOrganisation}"
|
||||
update="formNouvelleOrganisation"
|
||||
styleClass="p-button-outlined p-button-warning"
|
||||
immediate="true">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Réinitialiser le formulaire ? Toutes les données seront perdues."
|
||||
icon="pi pi-exclamation-triangle"/>
|
||||
</p:commandButton>
|
||||
|
||||
<!-- DRY/WOU: button-secondary pour Annuler -->
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler"/>
|
||||
<ui:param name="icon" value="pi pi-times"/>
|
||||
<ui:param name="outcome" value="/pages/secure/organisation/liste"/>
|
||||
</ui:include>
|
||||
|
||||
<!-- Bouton Créer l'organisation (MethodExpression direct) -->
|
||||
<p:commandButton value="Créer l'organisation"
|
||||
icon="pi pi-check"
|
||||
action="#{organisationsBean.creerOrganisation}"
|
||||
update="formNouvelleOrganisation messages"
|
||||
styleClass="p-button-success p-button-lg"
|
||||
validateClient="true">
|
||||
<p:confirm header="Confirmation de création"
|
||||
message="Créer cette organisation avec les informations saisies ?"
|
||||
icon="pi pi-question-circle"/>
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler"/>
|
||||
<ui:param name="icon" value="pi pi-times"/>
|
||||
<ui:param name="outcome" value="/pages/secure/organisation/liste"/>
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<div class="card">
|
||||
<h5 class="mb-3">Informations de l'Organisation</h5>
|
||||
<ui:include src="/ui/includes/organisation-form.xhtml">
|
||||
<ui:param name="model" value="#{organisationsBean.nouvelleOrganisation}" />
|
||||
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<!-- Dialog de confirmation global (DRY/WOU: confirm-dialog) -->
|
||||
<ui:include src="/templates/components/dialogs/confirm-dialog.xhtml" />
|
||||
|
||||
<div class="mt-3 flex justify-content-end gap-2">
|
||||
<!-- DRY/WOU: button-secondary pour navigation -->
|
||||
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Annuler"/>
|
||||
<ui:param name="icon" value="pi pi-times"/>
|
||||
<ui:param name="outcome" value="/pages/secure/organisation/liste"/>
|
||||
</ui:include>
|
||||
<!-- Bouton Créer : p:commandButton direct car action avec méthode backend -->
|
||||
<p:commandButton value="Créer"
|
||||
icon="pi pi-check"
|
||||
action="#{organisationsBean.creerOrganisation}"
|
||||
update=":formNouvelleOrganisation:messages"
|
||||
styleClass="ui-button-success" />
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -164,9 +164,11 @@
|
||||
<div class="field">
|
||||
<p:outputLabel for="devise" value="Devise" />
|
||||
<p:selectOneMenu id="devise" value="#{configBean.config.devise}">
|
||||
<f:selectItem itemLabel="FCFA (XOF)" itemValue="XOF" />
|
||||
<f:selectItem itemLabel="Euro (EUR)" itemValue="EUR" />
|
||||
<f:selectItem itemLabel="Dollar (USD)" itemValue="USD" />
|
||||
<f:selectItem itemLabel="XOF — Franc CFA (UEMOA)" itemValue="XOF" />
|
||||
<f:selectItem itemLabel="XAF — Franc CFA (CEMAC)" itemValue="XAF" />
|
||||
<f:selectItem itemLabel="MAD — Dirham marocain" itemValue="MAD" />
|
||||
<f:selectItem itemLabel="NGN — Naira nigérian" itemValue="NGN" />
|
||||
<f:selectItem itemLabel="GHS — Cédi ghanéen" itemValue="GHS" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -156,11 +156,12 @@
|
||||
<p:selectOneMenu id="devise"
|
||||
value="#{configurationBean.deviseDefaut}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="FCFA (Franc CFA)" itemValue="XOF" />
|
||||
<f:selectItem itemLabel="EUR (Euro)" itemValue="EUR" />
|
||||
<f:selectItem itemLabel="USD (Dollar)" itemValue="USD" />
|
||||
<f:selectItem itemLabel="GHS (Cédi Ghana)" itemValue="GHS" />
|
||||
<f:selectItem itemLabel="NGN (Naira Nigeria)" itemValue="NGN" />
|
||||
<f:selectItem itemLabel="XOF — Franc CFA (UEMOA)" itemValue="XOF" />
|
||||
<f:selectItem itemLabel="XAF — Franc CFA (CEMAC)" itemValue="XAF" />
|
||||
<f:selectItem itemLabel="MAD — Dirham marocain" itemValue="MAD" />
|
||||
<f:selectItem itemLabel="GHS — Cédi ghanéen" itemValue="GHS" />
|
||||
<f:selectItem itemLabel="NGN — Naira nigérian" itemValue="NGN" />
|
||||
<f:selectItem itemLabel="ZAR — Rand sud-africain" itemValue="ZAR" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -119,10 +119,7 @@
|
||||
<p:selectOneMenu id="filterType"
|
||||
value="#{entitesGestionBean.filtres.type}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Club Lions" itemValue="CLUB_LIONS" />
|
||||
<f:selectItem itemLabel="LEO Club" itemValue="LEO_CLUB" />
|
||||
<f:selectItem itemLabel="Branche" itemValue="BRANCHE" />
|
||||
<f:selectItems value="#{entitesGestionBean.typesSelectItems}" />
|
||||
<p:ajax update=":formTableEntites:dtEntites" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
@@ -145,11 +142,7 @@
|
||||
<p:selectOneMenu id="filterRegion"
|
||||
value="#{entitesGestionBean.filtres.region}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes les régions" itemValue="" />
|
||||
<f:selectItem itemLabel="Dakar" itemValue="DAKAR" />
|
||||
<f:selectItem itemLabel="Thiès" itemValue="THIES" />
|
||||
<f:selectItem itemLabel="Kaolack" itemValue="KAOLACK" />
|
||||
<f:selectItem itemLabel="Saint-Louis" itemValue="SAINT_LOUIS" />
|
||||
<f:selectItems value="#{entitesGestionBean.regionsDisponibles}" />
|
||||
<p:ajax update=":formTableEntites:dtEntites" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
@@ -259,26 +252,23 @@
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:8rem" exportable="false">
|
||||
<h:form id="formActions#{entite.id}">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
|
||||
action="#{entitesGestionBean.voirEntite(entite)}"
|
||||
title="Voir détails" />
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
|
||||
onclick="PF('dlgModifierEntite').show();"
|
||||
title="Modifier">
|
||||
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
|
||||
</p:commandButton>
|
||||
<p:commandButton icon="pi pi-cog"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
|
||||
onclick="PF('dlgActionsEntite').show();"
|
||||
title="Actions">
|
||||
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</h:form>
|
||||
<div class="flex gap-1">
|
||||
<p:button icon="pi pi-eye"
|
||||
title="Voir détails"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
|
||||
href="/pages/secure/organisation/detail.xhtml?id=#{entite.id}" />
|
||||
<p:button icon="pi pi-pencil"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
|
||||
title="Modifier"
|
||||
href="/pages/secure/organisation/detail.xhtml?id=#{entite.id}&mode=edit" />
|
||||
<p:commandButton icon="pi pi-cog"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
|
||||
title="Actions"
|
||||
update=":formActionsEntite"
|
||||
oncomplete="PF('dlgActionsEntite').show();">
|
||||
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
@@ -308,25 +298,19 @@
|
||||
<label for="newType" class="block text-900 font-medium mb-2">Type d'entité *</label>
|
||||
<p:selectOneMenu id="newType"
|
||||
value="#{entitesGestionBean.nouvelleEntite.type}"
|
||||
required="true">
|
||||
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
|
||||
<f:selectItem itemLabel="Club Lions" itemValue="CLUB_LIONS" />
|
||||
<f:selectItem itemLabel="LEO Club" itemValue="LEO_CLUB" />
|
||||
<f:selectItem itemLabel="Branche" itemValue="BRANCHE" />
|
||||
required="true"
|
||||
requiredMessage="Le type d'entité est requis.">
|
||||
<f:selectItems value="#{entitesGestionBean.typesSelectItemsForForm}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="newType" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
<label for="newRegion" class="block text-900 font-medium mb-2">Région *</label>
|
||||
<p:selectOneMenu id="newRegion"
|
||||
value="#{entitesGestionBean.nouvelleEntite.region}"
|
||||
required="true">
|
||||
<f:selectItem itemLabel="Sélectionner une région" itemValue="" />
|
||||
<f:selectItem itemLabel="Dakar" itemValue="DAKAR" />
|
||||
<f:selectItem itemLabel="Thiès" itemValue="THIES" />
|
||||
<f:selectItem itemLabel="Kaolack" itemValue="KAOLACK" />
|
||||
<f:selectItem itemLabel="Saint-Louis" itemValue="SAINT_LOUIS" />
|
||||
</p:selectOneMenu>
|
||||
<label for="newRegion" class="block text-900 font-medium mb-2">Région</label>
|
||||
<p:inputText id="newRegion"
|
||||
value="#{entitesGestionBean.nouvelleEntite.region}"
|
||||
placeholder="Ex: Lagunes, Dakar, Abidjan..."
|
||||
maxlength="100" />
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-6">
|
||||
@@ -394,38 +378,47 @@
|
||||
<p:commandButton value="Gérer les membres"
|
||||
icon="pi pi-users"
|
||||
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
|
||||
action="#{entitesGestionBean.gererMembres}" />
|
||||
action="#{entitesGestionBean.gererMembres}"
|
||||
ajax="false" />
|
||||
|
||||
<p:commandButton value="Configuration"
|
||||
icon="pi pi-cog"
|
||||
<p:commandButton value="Voir / Configurer"
|
||||
icon="pi pi-eye"
|
||||
styleClass="ui-button-warning ui-button-outlined ui-button-sm w-full"
|
||||
action="#{entitesGestionBean.configurerEntite}" />
|
||||
action="#{entitesGestionBean.configurerEntite}"
|
||||
ajax="false" />
|
||||
|
||||
<p:commandButton value="Rapports"
|
||||
<p:commandButton value="Rapports & Stats"
|
||||
icon="pi pi-chart-bar"
|
||||
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
|
||||
action="#{entitesGestionBean.voirRapports}" />
|
||||
action="#{entitesGestionBean.voirRapports}"
|
||||
ajax="false" />
|
||||
|
||||
<p:commandButton value="Suspendre"
|
||||
icon="pi pi-ban"
|
||||
styleClass="ui-button-danger ui-button-outlined ui-button-sm w-full"
|
||||
action="#{entitesGestionBean.suspendreEntite}"
|
||||
onclick="return confirm('Êtes-vous sûr de vouloir suspendre cette entité ?');"
|
||||
update=":formTableEntites:dtEntites :formActionsEntite"
|
||||
oncomplete="PF('dlgActionsEntite').hide();"
|
||||
onclick="return confirm('Suspendre cette entité ?');"
|
||||
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'ACTIVE'}" />
|
||||
|
||||
<p:commandButton value="Réactiver"
|
||||
icon="pi pi-check"
|
||||
styleClass="ui-button-success ui-button-outlined ui-button-sm w-full"
|
||||
action="#{entitesGestionBean.reactiverEntite}"
|
||||
update=":formTableEntites:dtEntites :formActionsEntite"
|
||||
oncomplete="PF('dlgActionsEntite').hide();"
|
||||
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'SUSPENDUE'}" />
|
||||
|
||||
<hr class="surface-border" />
|
||||
|
||||
<p:commandButton value="Supprimer"
|
||||
<p:commandButton value="Supprimer définitivement"
|
||||
icon="pi pi-trash"
|
||||
styleClass="ui-button-danger ui-button-sm w-full"
|
||||
onclick="return confirm('ATTENTION: Cette action est irréversible. Confirmer la suppression ?');"
|
||||
action="#{entitesGestionBean.supprimerEntite}" />
|
||||
action="#{entitesGestionBean.supprimerEntite}"
|
||||
update=":formTableEntites:dtEntites"
|
||||
oncomplete="PF('dlgActionsEntite').hide();"
|
||||
onclick="return confirm('ATTENTION : action irréversible. Confirmer la suppression ?');" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
<ui:include src="/ui/includes/organisation-form.xhtml">
|
||||
<ui:param name="model" value="#{organisationsBean.nouvelleOrganisation}" />
|
||||
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
<ui:param name="completionBean" value="#{organisationsBean}" />
|
||||
</ui:include>
|
||||
|
||||
<f:facet name="footer">
|
||||
@@ -191,6 +192,7 @@
|
||||
<ui:include src="/ui/includes/organisation-form.xhtml">
|
||||
<ui:param name="model" value="#{organisationsBean.organisationSelectionnee}" />
|
||||
<ui:param name="typesItems" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
<ui:param name="completionBean" value="#{organisationsBean}" />
|
||||
</ui:include>
|
||||
|
||||
<f:facet name="footer">
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
|
||||
|
||||
<!--
|
||||
Composant bouton icône seule réutilisable (WOU/DRY)
|
||||
@@ -20,9 +21,9 @@
|
||||
<ui:fragment rendered="#{empty rendered or rendered}">
|
||||
<p:commandButton
|
||||
icon="#{icon}"
|
||||
action="#{action}"
|
||||
update="#{update}"
|
||||
onclick="#{onclick}"
|
||||
type="button"
|
||||
disabled="#{not empty disabled and disabled}"
|
||||
styleClass="#{not empty rounded and rounded ? 'ui-button-rounded' : ''} #{not empty text and text ? 'ui-button-text' : ''} #{not empty severity ? 'ui-button-' += severity : ''} #{not empty styleClass ? styleClass : ''}"
|
||||
title="#{title}" />
|
||||
|
||||
@@ -15,21 +15,21 @@
|
||||
-->
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<h:panelGroup layout="block"
|
||||
styleClass="card #{bgColor == 'blue' ? 'bg-blue-100 border-left-3 border-blue-500' : (bgColor == 'green' ? 'bg-green-100 border-left-3 border-green-500' : (bgColor == 'orange' ? 'bg-orange-100 border-left-3 border-orange-500' : 'bg-blue-100 border-left-3 border-blue-500'))}">
|
||||
<h:panelGroup layout="block"
|
||||
styleClass="card bg-#{bgColor}-100 border-left-3 border-#{bgColor}-500">
|
||||
<div class="flex justify-content-between">
|
||||
<div>
|
||||
<h:panelGroup layout="block"
|
||||
styleClass="font-bold text-xl #{bgColor == 'blue' ? 'text-blue-900' : (bgColor == 'green' ? 'text-green-900' : (bgColor == 'orange' ? 'text-orange-900' : 'text-blue-900'))}">
|
||||
styleClass="font-bold text-xl text-#{bgColor}-900">
|
||||
<h:outputText value="#{value}" />
|
||||
</h:panelGroup>
|
||||
<h:panelGroup layout="block"
|
||||
styleClass="#{bgColor == 'blue' ? 'text-blue-700' : (bgColor == 'green' ? 'text-green-700' : (bgColor == 'orange' ? 'text-orange-700' : 'text-blue-700'))}">
|
||||
styleClass="text-#{bgColor}-700">
|
||||
<h:outputText value="#{label}" />
|
||||
</h:panelGroup>
|
||||
</div>
|
||||
<h:panelGroup layout="block"
|
||||
styleClass="text-white border-round text-center #{bgColor == 'blue' ? 'bg-blue-500' : (bgColor == 'green' ? 'bg-green-500' : (bgColor == 'orange' ? 'bg-orange-500' : 'bg-blue-500'))}"
|
||||
styleClass="text-white border-round text-center bg-#{bgColor}-500"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
|
||||
<i class="#{icon} text-lg"></i>
|
||||
</h:panelGroup>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui">
|
||||
|
||||
<!--
|
||||
Composant colonne Texte avec icône réutilisable - DRY/WOU
|
||||
@@ -14,12 +12,13 @@
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<p:column headerText="#{headerText}"
|
||||
style="#{not empty width ? 'width: ' += width : ''}">
|
||||
<p:column headerText="#{headerText}" sortBy="#{sortBy}" filterBy="#{filterBy}"
|
||||
filterMatchMode="#{empty filterMatchMode ? 'contains' : filterMatchMode}"
|
||||
style="#{not empty width ? 'width: ' += width : ''}">
|
||||
<ui:fragment rendered="#{not empty icon}">
|
||||
<i class="#{icon} mr-1"></i>
|
||||
<i class="#{icon} mr-1 text-primary"></i>
|
||||
</ui:fragment>
|
||||
<h:outputText value="#{text}"/>
|
||||
<h:outputText value="#{text}" styleClass="#{not empty styleClass ? styleClass : ''}" />
|
||||
<ui:insert />
|
||||
</p:column>
|
||||
</ui:composition>
|
||||
|
||||
</ui:composition>
|
||||
@@ -11,22 +11,19 @@
|
||||
<ui:param name="value" value="#{bean.property}"/>
|
||||
<ui:param name="multiline" value="true" />
|
||||
</ui:include>
|
||||
Note : utilise l'opérateur EL `empty` pour gérer correctement null,
|
||||
chaînes vides, 0 (entier valide) et false (booléen valide).
|
||||
-->
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="text-600 text-sm mb-1">
|
||||
<h:outputText value="#{label}" />
|
||||
<h:panelGroup rendered="#{not empty value}">
|
||||
<div class="mb-4">
|
||||
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--text-color-secondary);opacity:.7;margin-bottom:.35rem;">
|
||||
<h:outputText value="#{label}" />
|
||||
</div>
|
||||
<div style="font-size:.925rem;font-weight:600;color:var(--text-color);#{multiline ? 'white-space:pre-line;line-height:1.6;' : ''}">
|
||||
<h:outputText value="#{value}" escape="true" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-900">
|
||||
<h:outputText value="#{value}"
|
||||
rendered="#{value != null}"
|
||||
escape="true"
|
||||
style="#{multiline ? 'white-space: pre-line;' : ''}" />
|
||||
<h:outputText value="Non renseigné"
|
||||
rendered="#{value == null}"
|
||||
styleClass="text-400" />
|
||||
</div>
|
||||
</div>
|
||||
</h:panelGroup>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
|
||||
|
||||
@@ -1,57 +1,12 @@
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui">
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
|
||||
|
||||
<div class="layout-footer">
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<span class="footer-menutitle">NAVIGATION</span>
|
||||
<ul>
|
||||
<li><a href="/pages/secure/dashboard">Tableau de Bord</a></li>
|
||||
<li><a href="/pages/secure/membre/liste">Membres</a></li>
|
||||
<li><a href="/pages/secure/adhesion/liste">Adhésions</a></li>
|
||||
<li><a href="/pages/secure/aide/documentation">Aide</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<span class="footer-menutitle"></span>
|
||||
<ul>
|
||||
<li><a href="/pages/secure/evenement/calendrier">Calendrier</a></li>
|
||||
<li><a href="/pages/secure/cotisation/historique">Cotisations</a></li>
|
||||
<li><a href="/pages/secure/rapport/membres">Rapports</a></li>
|
||||
<li><a href="/pages/secure/admin/parametres">Paramètres</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<span class="footer-menutitle">CONTACT</span>
|
||||
<ul>
|
||||
<li>+221 77 123 45 67</li>
|
||||
<li>Plateau, Dakar,</li>
|
||||
<li>Sénégal</li>
|
||||
<li>contact@unionflow.sn</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-5">
|
||||
<span class="footer-menutitle">NEWSLETTER</span>
|
||||
<span class="footer-subtitle">Rejoignez notre newsletter pour être informé des nouvelles fonctionnalités.</span>
|
||||
<h:form>
|
||||
<div class="newsletter-input">
|
||||
<p:inputText placeholder="adresse email" />
|
||||
<p:commandButton value="S'abonner" styleClass="ui-button-secondary" />
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="footer-bottom">
|
||||
<h4>UnionFlow</h4>
|
||||
<h6>Copyright © Lions Dev Team</h6>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="footer-bottom" style="justify-content:space-between;align-items:center;flex-wrap:wrap;gap:.5rem;">
|
||||
<h4 style="margin:0;">UnionFlow</h4>
|
||||
<h6 style="margin:0;opacity:.7;">Copyright © Lions Dev Team</h6>
|
||||
</div>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<p:menuitem id="m_dashboard" value="Tableau de Bord" icon="pi pi-home" outcome="/pages/secure/dashboard" />
|
||||
|
||||
<!-- Super Administration -->
|
||||
<p:submenu id="m_super_admin" label="Super Administration" icon="pi pi-shield">
|
||||
<p:submenu id="m_super_admin" label="Super Administration" icon="pi pi-shield" rendered="#{menuBean.superAdminMenuVisible}">
|
||||
<p:menuitem id="m_super_dashboard" value="Dashboard Super-Admin" icon="pi pi-chart-bar" outcome="/pages/super-admin/dashboard" />
|
||||
<p:menuitem id="m_gestion_entites" value="Gestion des Entités" icon="pi pi-sitemap" outcome="/pages/super-admin/entites/gestion" />
|
||||
<p:menuitem id="m_gestion_types_organisations" value="Types d'Organisation" icon="pi pi-tags" outcome="/pages/super-admin/types/organisations" />
|
||||
@@ -29,140 +29,154 @@
|
||||
</p:submenu>
|
||||
|
||||
<!-- Administration Générale -->
|
||||
<p:submenu id="m_administration" label="Administration" icon="pi pi-cog">
|
||||
<p:menuitem id="m_gestion_cotisations" value="Gestion Cotisations" icon="pi pi-dollar" outcome="/pages/admin/cotisations/gestion" />
|
||||
<p:menuitem id="m_gestion_evenements" value="Gestion Événements" icon="pi pi-calendar" outcome="/pages/admin/evenements/gestion" />
|
||||
<p:menuitem id="m_demandes_aide" value="Demandes d'Aide" icon="pi pi-heart" outcome="/pages/admin/demandes/gestion" />
|
||||
<p:menuitem id="m_rapports_stats" value="Rapports et Statistiques" icon="pi pi-chart-bar" outcome="/pages/admin/rapports/statistiques" />
|
||||
<p:submenu id="m_administration" label="Administration" icon="pi pi-cog" rendered="#{menuBean.administrationMenuVisible}">
|
||||
<p:menuitem id="m_gestion_cotisations" value="Gestion Cotisations" icon="pi pi-dollar" outcome="/pages/admin/cotisations/gestion" rendered="#{menuBean.cotisationsAdminVisible}" />
|
||||
<p:menuitem id="m_gestion_evenements" value="Gestion Événements" icon="pi pi-calendar" outcome="/pages/admin/evenements/gestion" rendered="#{menuBean.creationEvenementVisible}" />
|
||||
<p:menuitem id="m_demandes_aide" value="Demandes d'Aide" icon="pi pi-heart" outcome="/pages/admin/demandes/gestion" rendered="#{menuBean.traitementAideVisible}" />
|
||||
<p:menuitem id="m_rapports_stats" value="Rapports et Statistiques" icon="pi pi-chart-bar" outcome="/pages/admin/rapports/statistiques" rendered="#{menuBean.rapportsMenuVisible}" />
|
||||
<p:menuitem id="m_gestion_documents" value="Gestion Documents" icon="pi pi-folder" outcome="/pages/admin/documents/gestion" />
|
||||
<p:menuitem id="m_parametres" value="Paramètres Système" icon="pi pi-sliders-h" url="#" />
|
||||
<p:menuitem id="m_utilisateurs" value="Gestion Utilisateurs" icon="pi pi-users" outcome="/pages/admin/utilisateurs/gestion" />
|
||||
<p:menuitem id="m_roles" value="Rôles et Permissions" icon="pi pi-key" outcome="/pages/super-admin/roles/gestion" />
|
||||
<p:menuitem id="m_audit" value="Journal d'Audit" icon="pi pi-file-o" outcome="/pages/admin/audit/journal" />
|
||||
<p:menuitem id="m_parametres" value="Paramètres Système" icon="pi pi-sliders-h" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_roles" value="Rôles Applicatifs" icon="pi pi-key" outcome="/pages/super-admin/roles/gestion" rendered="#{menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_audit" value="Journal d'Audit Applicatif" icon="pi pi-file-o" outcome="/pages/admin/audit/journal" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:separator rendered="#{menuBean.keycloakUserManagerVisible}" />
|
||||
<!-- Lions User Manager - Gestion Keycloak -->
|
||||
<p:menuitem id="m_user_manager_list" value="Utilisateurs Keycloak" icon="pi pi-users-cog" outcome="/pages/user-manager/users/list" rendered="#{menuBean.keycloakUserManagerVisible}" />
|
||||
<p:menuitem id="m_user_manager_create" value="Nouvel Utilisateur Keycloak" icon="pi pi-user-plus" outcome="/pages/user-manager/users/create" rendered="#{menuBean.keycloakUserManagerVisible}" />
|
||||
<p:menuitem id="m_user_manager_roles" value="Rôles Keycloak" icon="pi pi-shield" outcome="/pages/user-manager/roles/list" rendered="#{menuBean.keycloakUserManagerVisible}" />
|
||||
<p:menuitem id="m_user_manager_audit" value="Journal d'Audit Keycloak" icon="pi pi-history" outcome="/pages/user-manager/audit/logs" rendered="#{menuBean.keycloakUserManagerVisible}" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion des Membres -->
|
||||
<p:submenu id="m_membres" label="Gestion des Membres" icon="pi pi-users">
|
||||
<!-- Annuaire des Membres (MEMBRE_ACTIF et plus - Consultation) -->
|
||||
<p:submenu id="m_annuaire" label="Annuaire des Membres" icon="pi pi-users" rendered="#{menuBean.annuaireMembresVisible}">
|
||||
<p:menuitem id="m_liste_membres_lecture" value="Liste des Membres" icon="pi pi-list" outcome="/pages/secure/membre/liste" />
|
||||
<p:menuitem id="m_recherche_membres" value="Rechercher un Membre" icon="pi pi-search" outcome="/pages/secure/membre/recherche" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion des Membres (SECRETAIRE, ADMIN - Administration) -->
|
||||
<p:submenu id="m_gestion_membres" label="Gestion des Membres" icon="pi pi-users-cog" rendered="#{menuBean.gestionMembresMenuVisible}">
|
||||
<p:menuitem id="m_inscription" value="Nouvelle Inscription" icon="pi pi-user-plus" outcome="/pages/secure/membre/inscription" />
|
||||
<p:menuitem id="m_liste_membres" value="Liste des Membres" icon="pi pi-list" outcome="/pages/secure/membre/liste" />
|
||||
<p:menuitem id="m_recherche_membres" value="Recherche Avancée" icon="pi pi-search" outcome="/pages/secure/membre/recherche" />
|
||||
<p:menuitem id="m_profil_membre" value="Mon Profil" icon="pi pi-user" outcome="/pages/secure/membre/profil" />
|
||||
<p:menuitem id="m_liste_membres" value="Liste Complète" icon="pi pi-list" outcome="/pages/secure/membre/liste" />
|
||||
<p:menuitem id="m_validation_membres" value="Validation Inscriptions" icon="pi pi-check-circle" outcome="/pages/secure/membre/validation" />
|
||||
<p:menuitem id="m_import_membres" value="Import en Masse" icon="pi pi-upload" outcome="/pages/secure/membre/import" />
|
||||
<p:menuitem id="m_export_membres" value="Export Membres" icon="pi pi-download" outcome="/pages/secure/membre/export" />
|
||||
<p:separator />
|
||||
<!-- Lions User Manager - Gestion Keycloak -->
|
||||
<p:menuitem id="m_user_manager_list" value="Utilisateurs Keycloak" icon="pi pi-users-cog" outcome="/pages/user-manager/users/list" />
|
||||
<p:menuitem id="m_user_manager_create" value="Nouvel Utilisateur" icon="pi pi-user-plus" outcome="/pages/user-manager/users/create" />
|
||||
<p:menuitem id="m_user_manager_roles" value="Gestion des Rôles" icon="pi pi-shield" outcome="/pages/user-manager/roles/list" />
|
||||
<p:menuitem id="m_user_manager_audit" value="Journal d'Audit" icon="pi pi-history" outcome="/pages/user-manager/audit/logs" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion des Organisations -->
|
||||
<p:submenu id="m_organisations" label="Organisations" icon="pi pi-building">
|
||||
<p:submenu id="m_organisations" label="Organisations" icon="pi pi-building" rendered="#{menuBean.organisationsMenuVisible}">
|
||||
<p:menuitem id="m_liste_organisations" value="Liste des Organisations" icon="pi pi-list" outcome="/pages/secure/organisation/liste" />
|
||||
<p:menuitem id="m_nouvelle_organisation" value="Nouvelle Organisation" icon="pi pi-plus" outcome="/pages/secure/organisation/nouvelle" />
|
||||
<p:menuitem id="m_statistiques_orga" value="Statistiques" icon="pi pi-chart-bar" url="#" />
|
||||
<p:menuitem id="m_statistiques_orga" value="Statistiques" icon="pi pi-chart-bar" outcome="/pages/secure/organisation/statistiques" />
|
||||
</p:submenu>
|
||||
|
||||
|
||||
<!-- Gestion des Adhésions -->
|
||||
<p:submenu id="m_adhesions" label="Gestion des Adhésions" icon="pi pi-bookmark">
|
||||
<p:submenu id="m_adhesions" label="Gestion des Adhésions" icon="pi pi-bookmark" rendered="#{menuBean.adhesionsMenuVisible}">
|
||||
<p:menuitem id="m_demande_adhesion" value="Nouvelle Demande" icon="pi pi-plus-circle" outcome="/pages/secure/adhesion/demande" />
|
||||
<p:menuitem id="m_validation_adhesion" value="Validation des Demandes" icon="pi pi-check-circle" outcome="/pages/secure/adhesion/validation" />
|
||||
<p:menuitem id="m_validation_adhesion" value="Validation des Demandes" icon="pi pi-check-circle" outcome="/pages/secure/adhesion/validation" rendered="#{menuBean.validationAdhesionVisible}" />
|
||||
<p:menuitem id="m_liste_adhesions" value="Toutes les Adhésions" icon="pi pi-list" outcome="/pages/secure/adhesion/liste" />
|
||||
<p:menuitem id="m_renouvellement" value="Renouvellements" icon="pi pi-refresh" outcome="/pages/secure/adhesion/renouvellement" />
|
||||
<p:menuitem id="m_cartes_membres" value="Cartes de Membres" icon="pi pi-id-card" url="#" />
|
||||
<p:menuitem id="m_historique_adhesions" value="Historique" icon="pi pi-history" url="#" />
|
||||
<p:menuitem id="m_cartes_membres" value="Cartes de Membres" icon="pi pi-id-card" outcome="/pages/secure/adhesion/cartes-membres" rendered="#{menuBean.secretaire or menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_historique_adhesions" value="Historique" icon="pi pi-history" outcome="/pages/secure/adhesion/historique" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion Financière -->
|
||||
<p:submenu id="m_finances" label="Gestion Financière" icon="pi pi-dollar">
|
||||
<p:menuitem id="m_cotisations" value="Cotisations" icon="pi pi-credit-card" outcome="/pages/secure/cotisation/paiement" />
|
||||
<p:menuitem id="m_historique_cotisations" value="Historique Paiements" icon="pi pi-history" outcome="/pages/secure/cotisation/historique" />
|
||||
<p:menuitem id="m_relances" value="Relances et Rappels" icon="pi pi-bell" outcome="/pages/secure/cotisation/relances" />
|
||||
<!-- Mes Finances (TOUS - Finances personnelles) -->
|
||||
<p:submenu id="m_mes_finances" label="Mes Finances" icon="pi pi-wallet" rendered="#{menuBean.mesFinancesMenuVisible}">
|
||||
<p:menuitem id="m_mes_cotisations" value="Mes Cotisations" icon="pi pi-credit-card" outcome="/pages/secure/membre/cotisations" rendered="#{menuBean.paiementCotisationVisible}" />
|
||||
<p:menuitem id="m_payer_cotisations" value="Payer mes Cotisations" icon="pi pi-dollar" outcome="/pages/secure/cotisation/paiement" rendered="#{menuBean.paiementCotisationVisible}" />
|
||||
<p:menuitem id="m_historique_finances" value="Historique" icon="pi pi-history" outcome="/pages/secure/cotisation/historique" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion Financière (TRESORIER, ADMIN - Administration finances) -->
|
||||
<p:submenu id="m_gestion_finances" label="Gestion Financière" icon="pi pi-dollar" rendered="#{menuBean.gestionFinancesMenuVisible}">
|
||||
<p:menuitem id="m_tresorerie" value="Trésorerie" icon="pi pi-wallet" outcome="/pages/secure/finance/tresorerie" />
|
||||
<p:menuitem id="m_budgets" value="Gestion des Budgets" icon="pi pi-chart-pie" outcome="/pages/secure/finance/budgets" />
|
||||
<p:menuitem id="m_comptabilite" value="Comptabilité" icon="pi pi-calculator" outcome="/pages/secure/comptabilite/gestion" />
|
||||
<p:menuitem id="m_relances" value="Relances Cotisations" icon="pi pi-bell" outcome="/pages/secure/cotisation/relances" />
|
||||
<p:menuitem id="m_rapports_cotisations" value="Rapports Cotisations" icon="pi pi-chart-bar" outcome="/pages/secure/cotisation/rapports" />
|
||||
<p:menuitem id="m_budgets" value="Gestion des Budgets" icon="pi pi-chart-pie" url="#" />
|
||||
<p:menuitem id="m_tresorerie" value="Trésorerie" icon="pi pi-wallet" url="#" />
|
||||
<p:menuitem id="m_comptabilite" value="Comptabilité" icon="pi pi-calculator" url="#" />
|
||||
<p:menuitem id="m_bilans" value="Bilans Financiers" icon="pi pi-chart-line" url="#" />
|
||||
<p:menuitem id="m_bilans" value="Bilans Financiers" icon="pi pi-chart-line" outcome="/pages/secure/finance/bilans" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Épargne et Crédit (RESPONSABLE_CREDIT, TRESORIER, ADMIN - Spécifique mutuelles) -->
|
||||
<p:submenu id="m_epargne_credit" label="Épargne et Crédit" icon="pi pi-money-bill" rendered="#{menuBean.epargneCreditVisible}">
|
||||
<p:menuitem id="m_demandes_credit" value="Demandes de Crédit" icon="pi pi-inbox" outcome="/pages/secure/credit/demandes" />
|
||||
<p:menuitem id="m_evaluation_credit" value="Évaluation Solvabilité" icon="pi pi-search" outcome="/pages/secure/credit/evaluation" />
|
||||
<p:menuitem id="m_suivi_credits" value="Suivi des Crédits" icon="pi pi-eye" outcome="/pages/secure/credit/suivi" />
|
||||
<p:menuitem id="m_remboursements" value="Remboursements" icon="pi pi-replay" outcome="/pages/secure/credit/remboursements" />
|
||||
<p:menuitem id="m_stats_credit" value="Statistiques Crédit" icon="pi pi-chart-bar" outcome="/pages/secure/credit/statistiques" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Aide Sociale -->
|
||||
<p:submenu id="m_aides" label="Aide Sociale" icon="pi pi-heart">
|
||||
<p:menuitem id="m_demande_aide" value="Nouvelle Demande" icon="pi pi-plus" outcome="/pages/secure/aide/demande" />
|
||||
<!-- Mes Demandes d'Aide (TOUS - Demandes personnelles) -->
|
||||
<p:submenu id="m_mes_aides" label="Aide Sociale" icon="pi pi-heart" rendered="#{menuBean.mesAidesSocialesMenuVisible}">
|
||||
<p:menuitem id="m_demande_aide" value="Faire une Demande" icon="pi pi-plus" outcome="/pages/secure/aide/demande" rendered="#{menuBean.demandeAideSocialeVisible}" />
|
||||
<p:menuitem id="m_mes_demandes_aide" value="Mes Demandes" icon="pi pi-list" outcome="/pages/secure/aide/requests" rendered="#{menuBean.mesDemandesAideVisible}" />
|
||||
<p:menuitem id="m_historique_aides" value="Historique" icon="pi pi-clock" outcome="/pages/secure/aide/historique" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion Aide Sociale (RESPONSABLE_SOCIAL, ADMIN - Administration aide sociale) -->
|
||||
<p:submenu id="m_gestion_aides" label="Gestion Aide Sociale" icon="pi pi-heart-fill" rendered="#{menuBean.gestionAidesSocialesMenuVisible}">
|
||||
<p:menuitem id="m_traitement_aide" value="Traitement des Demandes" icon="pi pi-cog" outcome="/pages/secure/aide/traitement" />
|
||||
<p:menuitem id="m_evaluation_aide" value="Évaluation Sociale" icon="pi pi-search" url="#" />
|
||||
<p:menuitem id="m_suivi_aide" value="Suivi des Bénéficiaires" icon="pi pi-eye" url="#" />
|
||||
<p:menuitem id="m_historique_aides" value="Historique des Aides" icon="pi pi-clock" outcome="/pages/secure/aide/historique" />
|
||||
<p:menuitem id="m_suivi_aide" value="Suivi des Bénéficiaires" icon="pi pi-eye" outcome="/pages/secure/aide/approved" />
|
||||
<p:menuitem id="m_statistiques_aides" value="Statistiques Sociales" icon="pi pi-chart-line" outcome="/pages/secure/aide/statistiques" />
|
||||
<p:menuitem id="m_fonds_solidarite" value="Fonds de Solidarité" icon="pi pi-heart-fill" url="#" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion des Événements -->
|
||||
<p:submenu id="m_evenements" label="Gestion des Événements" icon="pi pi-calendar">
|
||||
<p:menuitem id="m_creation_evenement" value="Nouvel Événement" icon="pi pi-plus" outcome="/pages/secure/evenement/creation" />
|
||||
<!-- Événements (TOUS - Participation) -->
|
||||
<p:submenu id="m_mes_evenements" label="Événements" icon="pi pi-calendar" rendered="#{menuBean.mesEvenementsMenuVisible}">
|
||||
<p:menuitem id="m_calendrier" value="Calendrier" icon="pi pi-calendar-plus" outcome="/pages/secure/evenement/calendrier" />
|
||||
<p:menuitem id="m_mes_inscriptions_events" value="Mes Inscriptions" icon="pi pi-list" outcome="/pages/secure/evenement/participants" rendered="#{menuBean.mesInscriptionsEvenementsVisible}" />
|
||||
<p:menuitem id="m_mes_reservations" value="Mes Réservations" icon="pi pi-ticket" outcome="/pages/secure/evenement/reservations" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion Événements (RESPONSABLE_EVENEMENTS, SECRETAIRE, ADMIN - Organisation) -->
|
||||
<p:submenu id="m_gestion_evenements" label="Gestion Événements" icon="pi pi-calendar-clock" rendered="#{menuBean.gestionEvenementsMenuVisible}">
|
||||
<p:menuitem id="m_creation_evenement" value="Nouvel Événement" icon="pi pi-plus" outcome="/pages/secure/evenement/creation" />
|
||||
<p:menuitem id="m_planification" value="Planification" icon="pi pi-clock" outcome="/pages/secure/evenement/planification" />
|
||||
<p:menuitem id="m_participation" value="Gestion des Participations" icon="pi pi-users" outcome="/pages/secure/evenement/participation" />
|
||||
<p:menuitem id="m_gestion_generale_evenements" value="Gestion Générale" icon="pi pi-cog" outcome="/pages/secure/evenement/gestion" />
|
||||
<p:menuitem id="m_logistique" value="Logistique" icon="pi pi-truck" outcome="/pages/secure/evenement/logistique" />
|
||||
<p:menuitem id="m_bilan_evenements" value="Bilan des Événements" icon="pi pi-chart-bar" outcome="/pages/secure/evenement/bilan" />
|
||||
<p:menuitem id="m_reservations" value="Réservations" icon="pi pi-ticket" outcome="/pages/secure/evenement/reservations" />
|
||||
<p:menuitem id="m_participation" value="Gestion Participations" icon="pi pi-users" outcome="/pages/secure/evenement/participation" />
|
||||
<p:menuitem id="m_gestion_generale_evenements" value="Gestion Générale" icon="pi pi-cog" outcome="/pages/secure/evenement/gestion" />
|
||||
<p:menuitem id="m_bilan_evenements" value="Bilans" icon="pi pi-chart-bar" outcome="/pages/secure/evenement/bilan" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Communication -->
|
||||
<p:submenu id="m_communication" label="Communication" icon="pi pi-envelope">
|
||||
<p:menuitem id="m_messages" value="Centre de Messages" icon="pi pi-inbox" url="#" />
|
||||
<p:menuitem id="m_notifications" value="Notifications" icon="pi pi-bell" url="#" />
|
||||
<p:menuitem id="m_annonces" value="Annonces Officielles" icon="pi pi-megaphone" url="#" />
|
||||
<p:menuitem id="m_newsletter" value="Newsletter" icon="pi pi-send" url="#" />
|
||||
<p:menuitem id="m_sms" value="Envoi SMS" icon="pi pi-mobile" url="#" />
|
||||
<p:menuitem id="m_emailing" value="Campagnes Email" icon="pi pi-at" url="#" />
|
||||
<p:menuitem id="m_reseaux_sociaux" value="Réseaux Sociaux" icon="pi pi-share-alt" url="#" />
|
||||
<!-- Communication (TOUS - Messages et notifications personnelles) -->
|
||||
<p:submenu id="m_mes_communications" label="Communication" icon="pi pi-envelope" rendered="#{menuBean.mesCommunicationsMenuVisible}">
|
||||
<p:menuitem id="m_mes_notifications" value="Mes Notifications" icon="pi pi-bell" outcome="/pages/secure/communication/notifications" />
|
||||
</p:submenu>
|
||||
|
||||
|
||||
<!-- Gestion Documentaire -->
|
||||
<p:submenu id="m_documents" label="Gestion Documentaire" icon="pi pi-folder">
|
||||
<p:submenu id="m_documents" label="Gestion Documentaire" icon="pi pi-folder" rendered="#{menuBean.documentsMenuVisible}">
|
||||
<p:menuitem id="m_bibliotheque" value="Bibliothèque" icon="pi pi-book" url="#" />
|
||||
<p:menuitem id="m_mes_documents" value="Mes Documents" icon="pi pi-file" url="#" />
|
||||
<p:menuitem id="m_modeles" value="Modèles et Templates" icon="pi pi-file-o" url="#" />
|
||||
<p:menuitem id="m_archivage" value="Archivage" icon="pi pi-archive" url="#" />
|
||||
<p:menuitem id="m_mes_documents" value="Mes Documents" icon="pi pi-file" outcome="/pages/secure/documents/mes-documents" />
|
||||
<p:menuitem id="m_modeles" value="Modèles et Templates" icon="pi pi-file-o" url="#" rendered="#{menuBean.secretaire or menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_archivage" value="Archivage" icon="pi pi-archive" url="#" rendered="#{menuBean.secretaire or menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_partage" value="Documents Partagés" icon="pi pi-share-alt" url="#" />
|
||||
<p:menuitem id="m_signatures" value="Signatures Électroniques" icon="pi pi-verified" url="#" />
|
||||
<p:menuitem id="m_workflow_doc" value="Workflow Documentaire" icon="pi pi-sitemap" url="#" />
|
||||
<p:menuitem id="m_signatures" value="Signatures Électroniques" icon="pi pi-verified" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_workflow_doc" value="Workflow Documentaire" icon="pi pi-sitemap" url="#" rendered="#{menuBean.secretaire or menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Formation et Développement -->
|
||||
<p:submenu id="m_formation" label="Formation et Développement" icon="pi pi-graduation-cap">
|
||||
<p:menuitem id="m_formations" value="Catalogue de Formations" icon="pi pi-book" url="#" />
|
||||
<p:menuitem id="m_inscriptions_formation" value="Inscriptions" icon="pi pi-user-plus" url="#" />
|
||||
<p:menuitem id="m_planning_formation" value="Planning des Formations" icon="pi pi-calendar" url="#" />
|
||||
<p:menuitem id="m_certifications" value="Certifications" icon="pi pi-verified" url="#" />
|
||||
<p:menuitem id="m_competences" value="Gestion des Compétences" icon="pi pi-star" url="#" />
|
||||
<p:menuitem id="m_e_learning" value="E-Learning" icon="pi pi-desktop" url="#" />
|
||||
<p:menuitem id="m_evaluations" value="Évaluations" icon="pi pi-check-square" url="#" />
|
||||
<!-- Formations (TOUS - Inscriptions et suivi) -->
|
||||
<p:submenu id="m_mes_formations" label="Formations" icon="pi pi-graduation-cap" rendered="#{menuBean.mesFormationsMenuVisible}">
|
||||
<p:menuitem id="m_info_formations" value="Informations" icon="pi pi-info-circle" outcome="/pages/secure/dashboard" />
|
||||
</p:submenu>
|
||||
|
||||
|
||||
<!-- Rapports et Analyses -->
|
||||
<p:submenu id="m_rapports" label="Rapports et Analyses" icon="pi pi-chart-bar">
|
||||
<p:menuitem id="m_tableaux_bord" value="Tableaux de Bord" icon="pi pi-chart-line" url="#" />
|
||||
<p:submenu id="m_rapports" label="Rapports et Analyses" icon="pi pi-chart-bar" rendered="#{menuBean.rapportsMenuVisible}">
|
||||
<p:menuitem id="m_tableaux_bord" value="Tableaux de Bord" icon="pi pi-chart-line" outcome="/pages/secure/rapport/tableaux-bord" />
|
||||
<p:menuitem id="m_rapport_membres" value="Rapport Membres" icon="pi pi-users" outcome="/pages/secure/rapport/membres" />
|
||||
<p:menuitem id="m_rapport_finances" value="Rapport Financier" icon="pi pi-dollar" outcome="/pages/secure/rapport/finances" />
|
||||
<p:menuitem id="m_rapport_finances" value="Rapport Financier" icon="pi pi-dollar" outcome="/pages/secure/rapport/finances" rendered="#{menuBean.rapportFinancierVisible}" />
|
||||
<p:menuitem id="m_rapport_activites" value="Rapport d'Activités" icon="pi pi-chart-line" outcome="/pages/secure/rapport/activites" />
|
||||
<p:menuitem id="m_indicateurs" value="Indicateurs de Performance" icon="pi pi-gauge" url="#" />
|
||||
<p:menuitem id="m_analyses_predicitives" value="Analyses Prédictives" icon="pi pi-eye" url="#" />
|
||||
<p:menuitem id="m_export" value="Exports Personnalisés" icon="pi pi-download" outcome="/pages/secure/rapport/export" />
|
||||
<p:menuitem id="m_indicateurs" value="Indicateurs de Performance" icon="pi pi-gauge" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_analyses_predicitives" value="Analyses Prédictives" icon="pi pi-eye" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_export" value="Exports Personnalisés" icon="pi pi-download" outcome="/pages/secure/rapport/export" rendered="#{menuBean.exportsPersonnalisesVisible}" />
|
||||
</p:submenu>
|
||||
|
||||
|
||||
<!-- Outils et Utilitaires -->
|
||||
<p:submenu id="m_outils" label="Outils et Utilitaires" icon="pi pi-wrench">
|
||||
<p:submenu id="m_outils" label="Outils et Utilitaires" icon="pi pi-wrench" rendered="#{menuBean.outilsMenuVisible}">
|
||||
<p:menuitem id="m_calculatrices" value="Calculatrices" icon="pi pi-calculator" url="#" />
|
||||
<p:menuitem id="m_generateurs" value="Générateurs" icon="pi pi-cog" url="#" />
|
||||
<p:menuitem id="m_imports" value="Imports de Données" icon="pi pi-upload" url="#" />
|
||||
<p:menuitem id="m_exports_masse" value="Exports en Masse" icon="pi pi-download" url="#" />
|
||||
<p:menuitem id="m_sauvegardes" value="Sauvegardes" icon="pi pi-save" url="#" />
|
||||
<p:menuitem id="m_synchronisation" value="Synchronisation" icon="pi pi-sync" url="#" />
|
||||
<p:menuitem id="m_maintenance" value="Maintenance" icon="pi pi-wrench" url="#" />
|
||||
<p:menuitem id="m_api_externe" value="APIs Externes" icon="pi pi-cloud" url="#" />
|
||||
<p:menuitem id="m_generateurs" value="Générateurs" icon="pi pi-cog" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_imports" value="Imports de Données" icon="pi pi-upload" url="#" rendered="#{menuBean.importExportMembreVisible}" />
|
||||
<p:menuitem id="m_exports_masse" value="Exports en Masse" icon="pi pi-download" outcome="/pages/secure/outils/exports-masse" rendered="#{menuBean.exportsPersonnalisesVisible}" />
|
||||
<p:menuitem id="m_sauvegardes" value="Sauvegardes" icon="pi pi-save" url="#" rendered="#{menuBean.maintenanceVisible}" />
|
||||
<p:menuitem id="m_synchronisation" value="Synchronisation" icon="pi pi-sync" url="#" rendered="#{menuBean.adminOrganisation or menuBean.superAdmin}" />
|
||||
<p:menuitem id="m_maintenance" value="Maintenance" icon="pi pi-wrench" url="#" rendered="#{menuBean.maintenanceVisible}" />
|
||||
<p:menuitem id="m_api_externe" value="APIs Externes" icon="pi pi-cloud" url="#" rendered="#{menuBean.superAdmin}" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Mon Espace Personnel -->
|
||||
|
||||
@@ -4,104 +4,329 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
|
||||
<div class="layout-topbar">
|
||||
<!--
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ UnionFlow - Elite Topbar (Freya Design System) ║
|
||||
║ Real-time Session Monitor | Modern UI | Professional ║
|
||||
╚═══════════════════════════════════════════════════════════╝
|
||||
-->
|
||||
|
||||
<h:outputStylesheet library="css" name="topbar-elite.css" />
|
||||
|
||||
<div class="layout-topbar unionflow-elite">
|
||||
<div class="layout-topbar-wrapper">
|
||||
<!-- LEFT SECTION -->
|
||||
<div class="layout-topbar-left">
|
||||
<a href="#" class="menu-button">
|
||||
<i class="pi pi-bars"/>
|
||||
</a>
|
||||
<h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="layout-topbar-logo">
|
||||
<p:graphicImage name="images/#{ guestPreferences.lightLogo ? 'logo-freya-white.svg' : 'logo-freya.svg'}" library="freya-layout" />
|
||||
<p:graphicImage name="images/#{guestPreferences.lightLogo ? 'logo-freya-white.svg' : 'logo-freya.svg'}"
|
||||
library="freya-layout"
|
||||
alt="UnionFlow"
|
||||
title="Retour au tableau de bord"/>
|
||||
</h:link>
|
||||
<span class="app-version">v1.0</span>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- CENTER - Menu -->
|
||||
<ui:include src="/templates/components/layout/menu.xhtml" />
|
||||
|
||||
<!-- RIGHT SECTION -->
|
||||
<div class="layout-topbar-right">
|
||||
<ul class="layout-topbar-actions">
|
||||
<li class="topbar-item search-item ">
|
||||
<a href="#">
|
||||
|
||||
<!-- Search -->
|
||||
<li class="topbar-item search-item">
|
||||
<a href="#" title="Rechercher">
|
||||
<i class="topbar-icon pi pi-search"/>
|
||||
</a>
|
||||
<h:form>
|
||||
<h:panelGroup styleClass="search-input-wrapper">
|
||||
<p:inputText placeholder="Rechercher..." />
|
||||
<i class="pi pi-search"/>
|
||||
</h:panelGroup>
|
||||
</h:form>
|
||||
<ul>
|
||||
<h:form onsubmit="return false;">
|
||||
<h:panelGroup styleClass="search-input-wrapper">
|
||||
<p:inputText placeholder="Rechercher..." />
|
||||
<div class="search-dropdown">
|
||||
<h:form styleClass="search-form-elite">
|
||||
<div class="search-wrapper-elite">
|
||||
<i class="pi pi-search"/>
|
||||
</h:panelGroup>
|
||||
<p:inputText placeholder="Rechercher membres, organisations..."
|
||||
styleClass="search-input"/>
|
||||
<p:commandButton icon="pi pi-arrow-right"
|
||||
styleClass="p-button-rounded p-button-sm"/>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Notifications -->
|
||||
<li class="topbar-item notifications-item">
|
||||
<a href="#" title="Notifications">
|
||||
<i class="topbar-icon pi pi-bell"/>
|
||||
<span class="badge-count">3</span>
|
||||
</a>
|
||||
<ul class="notifications-dropdown">
|
||||
<li class="notif-header">
|
||||
<span class="font-semibold">Notifications</span>
|
||||
<span class="count-label">3 nouvelles</span>
|
||||
</li>
|
||||
<li class="divider"/>
|
||||
<li class="notif-item">
|
||||
<i class="pi pi-info-circle text-blue-500"/>
|
||||
<div>
|
||||
<div class="notif-title">Nouvelle adhésion</div>
|
||||
<div class="notif-time">Il y a 5 min</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="notif-item">
|
||||
<i class="pi pi-check-circle text-green-500"/>
|
||||
<div>
|
||||
<div class="notif-title">Cotisation validée</div>
|
||||
<div class="notif-time">Il y a 1h</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="divider"/>
|
||||
<li class="notif-footer">
|
||||
<a href="#" class="text-primary">Voir tout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="topbar-item user-profile">
|
||||
<a href="#" title="#{userSession.currentUser.nomComplet}">
|
||||
<div class="flex align-items-center">
|
||||
<div class="bg-primary text-white border-round flex align-items-center justify-content-center mr-2"
|
||||
style="width: 32px; height: 32px; font-size: 12px; font-weight: bold;">
|
||||
|
||||
<!-- User Profile -->
|
||||
<li class="topbar-item user-profile elite-user">
|
||||
<a href="#" class="profile-trigger">
|
||||
<div class="avatar-container">
|
||||
<div class="avatar bg-gradient-primary">
|
||||
#{userSession.currentUser.initiales}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<div class="text-900 font-medium">#{userSession.currentUser.nomComplet}</div>
|
||||
<div class="text-600 text-xs">#{userSession.typeCompte}</div>
|
||||
<span class="status-dot online"/>
|
||||
</div>
|
||||
|
||||
<div class="user-info">
|
||||
<div class="user-header">
|
||||
<span class="user-name">#{userSession.currentUser.nomComplet}</span>
|
||||
<span class="role-badge">#{userSession.typeCompte}</span>
|
||||
</div>
|
||||
<div class="session-timer">
|
||||
<h:panelGroup id="sessionTimerDisplay">
|
||||
<i class="#{sessionMonitor.timeIndicatorIcon} icon-sm"/>
|
||||
<span class="#{sessionMonitor.timeIndicatorClass} timer-text">
|
||||
#{sessionMonitor.formattedRemainingTime}
|
||||
</span>
|
||||
</h:panelGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i class="pi pi-angle-down arrow"/>
|
||||
</a>
|
||||
<ul>
|
||||
<li>
|
||||
<h:form>
|
||||
<p:commandLink action="#{navigationBean.goToProfile}">
|
||||
<i class="pi pi-user mr-2"></i>
|
||||
<span>Mon Profil</span>
|
||||
</p:commandLink>
|
||||
</h:form>
|
||||
</li>
|
||||
<li>
|
||||
<h:form>
|
||||
<p:commandLink action="#{navigationBean.goToSettings}">
|
||||
<i class="pi pi-cog mr-2"></i>
|
||||
<span>Paramètres</span>
|
||||
</p:commandLink>
|
||||
</h:form>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/pages/secure/messages.xhtml">
|
||||
<i class="pi pi-envelope mr-2"></i>
|
||||
<span>Messages</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="border-top-1 surface-border">
|
||||
<div class="p-2 text-xs text-600">
|
||||
<div>Entité: #{userSession.entite.nom}</div>
|
||||
<div>Connecté depuis:
|
||||
<span class="text-green-600">#{jwtTokenManager.timeUntilExpiration / 60} min</span>
|
||||
|
||||
<!-- User Dropdown -->
|
||||
<ul class="user-dropdown elite-dropdown">
|
||||
<!-- Header -->
|
||||
<li class="dropdown-header">
|
||||
<div class="header-content">
|
||||
<div class="header-avatar">
|
||||
<div class="avatar-lg bg-gradient-primary">
|
||||
#{userSession.currentUser.initiales}
|
||||
</div>
|
||||
<span class="status-indicator online">
|
||||
<i class="pi pi-circle-fill"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="header-info">
|
||||
<div class="name">#{userSession.currentUser.nomComplet}</div>
|
||||
<div class="email">#{userSession.currentUser.email}</div>
|
||||
<span class="role-tag">#{userSession.typeCompte}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<!-- Session Card -->
|
||||
<li class="session-card">
|
||||
<div class="card-content">
|
||||
<div class="info-row">
|
||||
<span class="label">
|
||||
<i class="pi pi-building"/>
|
||||
Organisation
|
||||
</span>
|
||||
<span class="value">#{userSession.entite.nom}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">
|
||||
<i class="#{sessionMonitor.timeIndicatorIcon}"/>
|
||||
Temps restant
|
||||
</span>
|
||||
<span class="value #{sessionMonitor.timeIndicatorClass}">
|
||||
#{sessionMonitor.formattedRemainingTime}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill"
|
||||
style="width: #{100 - sessionMonitor.sessionProgressPercent}%"/>
|
||||
</div>
|
||||
<div class="progress-label">
|
||||
#{sessionMonitor.remainingMinutes} min
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="divider"/>
|
||||
|
||||
<!-- Actions -->
|
||||
<li class="menu-section">
|
||||
<div class="section-title">
|
||||
<i class="pi pi-user"/>
|
||||
Mon Compte
|
||||
</div>
|
||||
<div class="section-items">
|
||||
<h:form>
|
||||
<p:commandLink action="#{navigationBean.goToProfile}"
|
||||
styleClass="menu-item">
|
||||
<i class="pi pi-user-edit"/>
|
||||
<span>Mon Profil</span>
|
||||
<i class="pi pi-angle-right arrow-right"/>
|
||||
</p:commandLink>
|
||||
</h:form>
|
||||
|
||||
<h:form>
|
||||
<p:commandLink action="#{navigationBean.goToSettings}"
|
||||
styleClass="menu-item">
|
||||
<i class="pi pi-cog"/>
|
||||
<span>Paramètres</span>
|
||||
<i class="pi pi-angle-right arrow-right"/>
|
||||
</p:commandLink>
|
||||
</h:form>
|
||||
|
||||
<a href="/pages/secure/messages.xhtml" class="menu-item">
|
||||
<i class="pi pi-envelope"/>
|
||||
<span>Messages</span>
|
||||
<span class="item-badge">2</span>
|
||||
<i class="pi pi-angle-right arrow-right"/>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="divider"/>
|
||||
|
||||
<!-- Preferences -->
|
||||
<li class="menu-section">
|
||||
<div class="section-title">
|
||||
<i class="pi pi-palette"/>
|
||||
Préférences
|
||||
</div>
|
||||
<div class="section-items">
|
||||
<a href="#" class="menu-item">
|
||||
<i class="pi pi-sun"/>
|
||||
<span>Thème</span>
|
||||
<span class="value-badge">Clair</span>
|
||||
</a>
|
||||
<a href="#" class="menu-item">
|
||||
<i class="pi pi-bell"/>
|
||||
<span>Notifications</span>
|
||||
<i class="pi pi-angle-right arrow-right"/>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="divider"/>
|
||||
|
||||
<!-- Support -->
|
||||
<li class="menu-section compact">
|
||||
<div class="section-items">
|
||||
<a href="#" class="menu-item">
|
||||
<i class="pi pi-question-circle text-blue-500"/>
|
||||
<span>Aide</span>
|
||||
</a>
|
||||
<a href="#" class="menu-item">
|
||||
<i class="pi pi-info-circle text-cyan-500"/>
|
||||
<span>À propos</span>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="divider logout-divider"/>
|
||||
|
||||
<!-- Logout -->
|
||||
<li class="logout-section">
|
||||
<h:form>
|
||||
<p:commandLink action="#{loginBean.logout}"
|
||||
styleClass="text-red-600"
|
||||
onclick="return confirm('Êtes-vous sûr de vouloir vous déconnecter ?');">
|
||||
<i class="pi pi-sign-out mr-2"></i>
|
||||
<p:commandLink styleClass="logout-btn"
|
||||
onclick="PF('logoutDialog').show(); return false;">
|
||||
<i class="pi pi-sign-out"/>
|
||||
<span>Déconnexion</span>
|
||||
<i class="pi pi-lock ml-auto"/>
|
||||
</p:commandLink>
|
||||
</h:form>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
<a href="#" class="layout-rightpanel-button">
|
||||
<i class="pi pi-arrow-left"></i>
|
||||
|
||||
<a href="#" class="layout-rightpanel-button" title="Configuration">
|
||||
<i class="pi pi-arrow-left"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</ui:composition>
|
||||
<!-- LOGOUT DIALOG -->
|
||||
<p:dialog id="logoutDialog"
|
||||
widgetVar="logoutDialog"
|
||||
header="Confirmation de déconnexion"
|
||||
modal="true"
|
||||
closable="true"
|
||||
styleClass="elite-dialog"
|
||||
responsive="true"
|
||||
width="450">
|
||||
|
||||
<div class="dialog-content">
|
||||
<div class="icon-wrapper">
|
||||
<i class="pi pi-sign-out icon-lg"/>
|
||||
</div>
|
||||
|
||||
<h3 class="dialog-title">Êtes-vous sûr de vouloir vous déconnecter ?</h3>
|
||||
|
||||
<div class="info-box">
|
||||
<div class="info-item">
|
||||
<i class="pi pi-user"/>
|
||||
<span>#{userSession.currentUser.nomComplet}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<i class="pi pi-clock"/>
|
||||
<span>Session: #{sessionMonitor.formattedRemainingTime}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="warning-text">
|
||||
<i class="pi pi-info-circle"/>
|
||||
Vous devrez vous reconnecter pour accéder à l'application.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="dialog-footer">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-outlined p-button-secondary"
|
||||
onclick="PF('logoutDialog').hide(); return false;"/>
|
||||
|
||||
<h:form>
|
||||
<p:commandButton value="Se déconnecter"
|
||||
icon="pi pi-sign-out"
|
||||
styleClass="p-button-danger"
|
||||
action="#{loginBean.logout}"
|
||||
onclick="PF('logoutDialog').hide();"/>
|
||||
</h:form>
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
|
||||
<!-- SESSION TIMER AUTO-REFRESH -->
|
||||
<h:form id="sessionTimerForm">
|
||||
<p:poll interval="5"
|
||||
listener="#{sessionMonitor.updateActivity}"
|
||||
update=":sessionTimerDisplay"
|
||||
global="false"
|
||||
autoStart="true"/>
|
||||
</h:form>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
xmlns:p="http://primefaces.org/ui">
|
||||
|
||||
<!--
|
||||
Fragment réutilisable pour le formulaire d'Organisation
|
||||
Fragment réutilisable pour le formulaire d'Organisation - Version Elite
|
||||
Paramètres attendus via <ui:param>:
|
||||
- model: l'objet cible (ex: #{organisationsBean.nouvelleOrganisation})
|
||||
- typesItems: la liste des SelectItem pour les types
|
||||
@@ -15,18 +15,26 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 1 : INFORMATIONS GÉNÉRALES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Informations générales" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<p:fieldset legend="📋 Informations générales" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Nom complet -->
|
||||
<div class="field col-12 md:col-8">
|
||||
<p:outputLabel for="nom" value="Nom complet *" styleClass="font-semibold" />
|
||||
<p:outputLabel for="nom" value="Nom complet" styleClass="font-semibold">
|
||||
<span class="text-red-500">*</span>
|
||||
</p:outputLabel>
|
||||
<p:inputText id="nom"
|
||||
value="#{model.nom}"
|
||||
required="true"
|
||||
requiredMessage="Le nom de l'organisation est requis."
|
||||
maxlength="200"
|
||||
placeholder="Ex: Association pour le développement durable" />
|
||||
placeholder="Ex: Association pour le développement durable">
|
||||
<f:validateLength minimum="3" maximum="200" />
|
||||
</p:inputText>
|
||||
<p:message for="nom" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-info-circle mr-1"/>
|
||||
Nom officiel complet de l'organisation (3-200 caractères)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Nom court / Sigle -->
|
||||
@@ -35,53 +43,91 @@
|
||||
<p:inputText id="nomCourt"
|
||||
value="#{model.nomCourt}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: ADD" />
|
||||
placeholder="Ex: ADD">
|
||||
<f:validateLength maximum="100" />
|
||||
</p:inputText>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-tag mr-1"/>
|
||||
Acronyme ou nom abrégé
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Type d'organisation -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="type" value="Type d'organisation *" styleClass="font-semibold" />
|
||||
<p:selectOneMenu id="type"
|
||||
value="#{model.typeAssociation}"
|
||||
<p:outputLabel for="type" value="Type d'organisation" styleClass="font-semibold">
|
||||
<span class="text-red-500">*</span>
|
||||
</p:outputLabel>
|
||||
<p:selectOneMenu id="type"
|
||||
value="#{model.typeAssociation}"
|
||||
required="true"
|
||||
requiredMessage="Le type d'organisation est requis.">
|
||||
<f:selectItem itemLabel="-- Sélectionnez un type --" itemValue="#{null}" noSelectionOption="true" />
|
||||
<f:selectItems value="#{typesItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="type" />
|
||||
<p:tooltip for="type" value="Catégorie juridique ou fonctionnelle de l'organisation" position="top"/>
|
||||
</div>
|
||||
|
||||
<!-- Statut de l'organisation -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="statut" value="Statut" styleClass="font-semibold">
|
||||
<span class="text-red-500">*</span>
|
||||
</p:outputLabel>
|
||||
<p:selectOneMenu id="statut"
|
||||
value="#{model.statut}"
|
||||
required="true"
|
||||
requiredMessage="Le statut de l'organisation est requis.">
|
||||
<f:selectItem itemLabel="✅ Active" itemValue="ACTIVE" />
|
||||
<f:selectItem itemLabel="🔨 En création" itemValue="EN_CREATION" />
|
||||
<f:selectItem itemLabel="⏸️ Inactive" itemValue="INACTIVE" />
|
||||
<f:selectItem itemLabel="⚠️ Suspendue" itemValue="SUSPENDUE" />
|
||||
<f:selectItem itemLabel="🚫 Dissoute" itemValue="DISSOUTE" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="statut" />
|
||||
<p:tooltip for="statut" value="État actuel de l'organisation - peut être modifié ultérieurement" position="top"/>
|
||||
</div>
|
||||
|
||||
<!-- Date de fondation -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="dateFondation" value="Date de fondation" styleClass="font-semibold" />
|
||||
<p:datePicker id="dateFondation"
|
||||
value="#{model.dateFondation}"
|
||||
pattern="dd/MM/yyyy"
|
||||
<p:datePicker id="dateFondation"
|
||||
value="#{model.dateFondation}"
|
||||
pattern="dd/MM/yyyy"
|
||||
showIcon="true"
|
||||
yearNavigator="true"
|
||||
yearRange="1900:2025"
|
||||
maxdate="#{null}"
|
||||
placeholder="jj/mm/aaaa" />
|
||||
<p:tooltip for="dateFondation" value="Date officielle de création de l'organisation" position="top"/>
|
||||
</div>
|
||||
|
||||
<!-- Numéro d'enregistrement -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="numEnreg" value="N° d'enregistrement" styleClass="font-semibold" />
|
||||
<p:inputText id="numEnreg"
|
||||
value="#{model.numeroRegistre}"
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="numEnreg" value="N° d'enregistrement / RCCM" styleClass="font-semibold" />
|
||||
<p:inputText id="numEnreg"
|
||||
value="#{model.numeroRegistre}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: RNA-W123456789" />
|
||||
placeholder="Ex: CI-ABJ-01-2024-B12-12345">
|
||||
<f:validateLength maximum="100" />
|
||||
</p:inputText>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-shield mr-1"/>
|
||||
Numéro d'immatriculation officiel (RCCM, RNA, etc.)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="description" value="Description" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="description"
|
||||
value="#{model.description}"
|
||||
rows="4"
|
||||
<p:inputTextarea id="description"
|
||||
value="#{model.description}"
|
||||
rows="4"
|
||||
maxlength="2000"
|
||||
placeholder="Décrivez brièvement l'organisation..."
|
||||
autoResize="false" />
|
||||
<small class="text-muted">#{2000 - (empty model.description ? 0 : model.description.length())} caractères restants</small>
|
||||
placeholder="Décrivez brièvement la mission, les objectifs et les activités principales de l'organisation..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="2000" />
|
||||
</p:inputTextarea>
|
||||
<p:message for="description" />
|
||||
<small class="text-500">Maximum 2000 caractères</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -89,76 +135,119 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 2 : COORDONNÉES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Coordonnées" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<p:fieldset legend="📞 Coordonnées" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Email principal -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="email" value="Email principal" styleClass="font-semibold" />
|
||||
<p:inputText id="email"
|
||||
value="#{model.email}"
|
||||
<p:inputText id="email"
|
||||
value="#{model.email}"
|
||||
maxlength="200"
|
||||
type="email"
|
||||
placeholder="contact@exemple.com" />
|
||||
placeholder="contact@organisation.com">
|
||||
<f:validateLength maximum="200" />
|
||||
</p:inputText>
|
||||
<p:message for="email" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-envelope mr-1"/>
|
||||
Email principal de contact
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Email secondaire -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="email2" value="Email secondaire" styleClass="font-semibold" />
|
||||
<p:inputText id="email2"
|
||||
value="#{model.emailSecondaire}"
|
||||
<p:inputText id="email2"
|
||||
value="#{model.emailSecondaire}"
|
||||
maxlength="200"
|
||||
type="email"
|
||||
placeholder="admin@exemple.com" />
|
||||
placeholder="admin@organisation.com">
|
||||
<f:validateLength maximum="200" />
|
||||
</p:inputText>
|
||||
<p:message for="email2" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-envelope mr-1"/>
|
||||
Email alternatif (optionnel)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Téléphone principal -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="telephone" value="Téléphone principal" styleClass="font-semibold" />
|
||||
<p:inputText id="telephone"
|
||||
value="#{model.telephone}"
|
||||
maxlength="20"
|
||||
placeholder="+225 XX XX XX XX XX" />
|
||||
<p:inputText id="telephone"
|
||||
value="#{model.telephone}"
|
||||
maxlength="30"
|
||||
placeholder="+225 07 00 00 00 00">
|
||||
<f:validateLength maximum="30" />
|
||||
</p:inputText>
|
||||
<p:message for="telephone" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-phone mr-1"/>
|
||||
Numéro principal avec indicatif pays
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Téléphone secondaire -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="telephone2" value="Téléphone secondaire" styleClass="font-semibold" />
|
||||
<p:inputText id="telephone2"
|
||||
value="#{model.telephoneSecondaire}"
|
||||
maxlength="20"
|
||||
placeholder="+225 XX XX XX XX XX" />
|
||||
<p:inputText id="telephone2"
|
||||
value="#{model.telephoneSecondaire}"
|
||||
maxlength="30"
|
||||
placeholder="+221 77 00 00 00">
|
||||
<f:validateLength maximum="30" />
|
||||
</p:inputText>
|
||||
<p:message for="telephone2" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-phone mr-1"/>
|
||||
Numéro alternatif (optionnel)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Site web -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="siteWeb" value="Site web" styleClass="font-semibold" />
|
||||
<p:inputText id="siteWeb"
|
||||
value="#{model.siteWeb}"
|
||||
<p:inputText id="siteWeb"
|
||||
value="#{model.siteWeb}"
|
||||
maxlength="500"
|
||||
placeholder="https://www.exemple.com" />
|
||||
placeholder="https://www.organisation.com">
|
||||
<f:validateLength maximum="500" />
|
||||
</p:inputText>
|
||||
<p:message for="siteWeb" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-globe mr-1"/>
|
||||
URL du site officiel (http:// ou https://)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Logo URL -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="logo" value="Logo (URL)" styleClass="font-semibold" />
|
||||
<p:inputText id="logo"
|
||||
value="#{model.logo}"
|
||||
<p:inputText id="logo"
|
||||
value="#{model.logo}"
|
||||
maxlength="500"
|
||||
placeholder="https://www.exemple.com/logo.png" />
|
||||
placeholder="https://www.organisation.com/logo.png">
|
||||
<f:validateLength maximum="500" />
|
||||
</p:inputText>
|
||||
<p:message for="logo" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-image mr-1"/>
|
||||
Lien vers le logo de l'organisation (PNG, JPG, SVG)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Réseaux sociaux -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="reseauxSociaux" value="Réseaux sociaux" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="reseauxSociaux"
|
||||
value="#{model.reseauxSociaux}"
|
||||
rows="3"
|
||||
<p:inputTextarea id="reseauxSociaux"
|
||||
value="#{model.reseauxSociaux}"
|
||||
rows="3"
|
||||
maxlength="1000"
|
||||
placeholder='Ex: {"facebook":"@pageOfficielle", "twitter":"@compte", "linkedin":"entreprise/nom"}'
|
||||
autoResize="false" />
|
||||
<small class="text-muted">Format JSON recommandé</small>
|
||||
placeholder='{"facebook":"@page_officielle", "twitter":"@compte", "linkedin":"entreprise/nom", "instagram":"@profil"}'
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="1000" />
|
||||
</p:inputTextarea>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-share-alt mr-1"/>
|
||||
Format JSON recommandé - Maximum 1000 caractères
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -166,80 +255,174 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 3 : LOCALISATION -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Localisation" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<p:fieldset legend="📍 Localisation" toggleable="true" collapsed="false" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Adresse complète -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="adresse" value="Adresse complète" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="adresse"
|
||||
value="#{model.adresse}"
|
||||
rows="2"
|
||||
<p:inputTextarea id="adresse"
|
||||
value="#{model.adresse}"
|
||||
rows="2"
|
||||
maxlength="500"
|
||||
placeholder="N° rue, quartier..."
|
||||
autoResize="false" />
|
||||
placeholder="N° de la parcelle, nom de la rue, quartier..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="500" />
|
||||
</p:inputTextarea>
|
||||
<small class="text-500">Maximum 500 caractères</small>
|
||||
</div>
|
||||
|
||||
<!-- Quartier / Commune -->
|
||||
<div class="field col-12 md:col-5">
|
||||
<p:outputLabel for="quartier" value="Quartier / Commune" styleClass="font-semibold" />
|
||||
<p:inputText id="quartier"
|
||||
value="#{model.quartier}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: Cocody, Hay Riad, Plateau...">
|
||||
<f:validateLength maximum="100" />
|
||||
</p:inputText>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-home mr-1"/>
|
||||
Quartier, commune ou arrondissement
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Ville -->
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="ville" value="Ville" styleClass="font-semibold" />
|
||||
<p:inputText id="ville"
|
||||
value="#{model.ville}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: Abidjan" />
|
||||
<p:autoComplete id="ville"
|
||||
value="#{model.ville}"
|
||||
completeMethod="#{completionBean.completerVilles}"
|
||||
minQueryLength="1"
|
||||
queryDelay="200"
|
||||
dropdown="true"
|
||||
forceSelection="false"
|
||||
placeholder="Ex: Abidjan"
|
||||
maxlength="100">
|
||||
<f:validateLength maximum="100" />
|
||||
</p:autoComplete>
|
||||
<p:tooltip for="ville" value="Commencez à taper pour voir les suggestions de villes de Côte d'Ivoire" position="top"/>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-building mr-1"/>
|
||||
Ville du siège social
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Code postal -->
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="codePostal" value="Code postal" styleClass="font-semibold" />
|
||||
<p:inputText id="codePostal"
|
||||
value="#{model.codePostal}"
|
||||
maxlength="10"
|
||||
placeholder="Ex: 01 BP 123" />
|
||||
<p:inputText id="codePostal"
|
||||
value="#{model.codePostal}"
|
||||
maxlength="20"
|
||||
placeholder="Ex: 01 BP 123, 75001…">
|
||||
<f:validateLength maximum="20" />
|
||||
</p:inputText>
|
||||
<p:message for="codePostal" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-map-marker mr-1"/>
|
||||
Format : 3-10 caractères (chiffres, lettres, tiret)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Région -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="region" value="Région" styleClass="font-semibold" />
|
||||
<p:inputText id="region"
|
||||
value="#{model.region}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: Lagunes" />
|
||||
<p:autoComplete id="region"
|
||||
value="#{model.region}"
|
||||
completeMethod="#{completionBean.completerRegions}"
|
||||
minQueryLength="1"
|
||||
queryDelay="200"
|
||||
dropdown="true"
|
||||
forceSelection="false"
|
||||
placeholder="Ex: Lagunes"
|
||||
maxlength="100">
|
||||
<f:validateLength maximum="100" />
|
||||
</p:autoComplete>
|
||||
<p:tooltip for="region" value="Commencez à taper pour voir les suggestions de régions de Côte d'Ivoire" position="top"/>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-map mr-1"/>
|
||||
Région administrative
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Pays -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="pays" value="Pays" styleClass="font-semibold" />
|
||||
<p:inputText id="pays"
|
||||
value="#{model.pays}"
|
||||
maxlength="100"
|
||||
placeholder="Ex: Côte d'Ivoire" />
|
||||
<p:selectOneMenu id="pays"
|
||||
value="#{model.pays}">
|
||||
<f:selectItem itemLabel="— Sélectionner —" itemValue="" />
|
||||
<!-- Afrique de l'Ouest (UEMOA / XOF) -->
|
||||
<f:selectItem itemLabel="🇨🇮 Côte d'Ivoire" itemValue="Côte d'Ivoire" />
|
||||
<f:selectItem itemLabel="🇸🇳 Sénégal" itemValue="Sénégal" />
|
||||
<f:selectItem itemLabel="🇲🇱 Mali" itemValue="Mali" />
|
||||
<f:selectItem itemLabel="🇧🇫 Burkina Faso" itemValue="Burkina Faso" />
|
||||
<f:selectItem itemLabel="🇬🇳 Guinée" itemValue="Guinée" />
|
||||
<f:selectItem itemLabel="🇳🇪 Niger" itemValue="Niger" />
|
||||
<f:selectItem itemLabel="🇹🇬 Togo" itemValue="Togo" />
|
||||
<f:selectItem itemLabel="🇧🇯 Bénin" itemValue="Bénin" />
|
||||
<f:selectItem itemLabel="🇬🇼 Guinée-Bissau" itemValue="Guinée-Bissau" />
|
||||
<!-- Afrique Centrale (CEMAC / XAF) -->
|
||||
<f:selectItem itemLabel="🇨🇲 Cameroun" itemValue="Cameroun" />
|
||||
<f:selectItem itemLabel="🇬🇦 Gabon" itemValue="Gabon" />
|
||||
<f:selectItem itemLabel="🇨🇬 Congo" itemValue="Congo" />
|
||||
<f:selectItem itemLabel="🇨🇩 RD Congo" itemValue="RD Congo" />
|
||||
<f:selectItem itemLabel="🇹🇩 Tchad" itemValue="Tchad" />
|
||||
<f:selectItem itemLabel="🇨🇫 Centrafrique" itemValue="Centrafrique" />
|
||||
<!-- Afrique du Nord -->
|
||||
<f:selectItem itemLabel="🇲🇦 Maroc" itemValue="Maroc" />
|
||||
<f:selectItem itemLabel="🇩🇿 Algérie" itemValue="Algérie" />
|
||||
<f:selectItem itemLabel="🇹🇳 Tunisie" itemValue="Tunisie" />
|
||||
<!-- Autres Afrique -->
|
||||
<f:selectItem itemLabel="🇳🇬 Nigeria" itemValue="Nigeria" />
|
||||
<f:selectItem itemLabel="🇬🇭 Ghana" itemValue="Ghana" />
|
||||
<f:selectItem itemLabel="🇰🇪 Kenya" itemValue="Kenya" />
|
||||
<f:selectItem itemLabel="🇿🇦 Afrique du Sud" itemValue="Afrique du Sud" />
|
||||
<f:selectItem itemLabel="🇷🇼 Rwanda" itemValue="Rwanda" />
|
||||
<f:selectItem itemLabel="🇪🇹 Éthiopie" itemValue="Éthiopie" />
|
||||
<!-- Diaspora / Europe -->
|
||||
<f:selectItem itemLabel="🇫🇷 France" itemValue="France" />
|
||||
<f:selectItem itemLabel="🇧🇪 Belgique" itemValue="Belgique" />
|
||||
<f:selectItem itemLabel="🌍 Autre" itemValue="Autre" />
|
||||
</p:selectOneMenu>
|
||||
<p:tooltip for="pays" value="Pays où l'organisation est enregistrée" position="top"/>
|
||||
</div>
|
||||
|
||||
<!-- Coordonnées GPS -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel value="Coordonnées GPS" styleClass="font-semibold" />
|
||||
<p:divider styleClass="my-3">
|
||||
<span class="text-600 font-semibold">
|
||||
<i class="pi pi-map-marker mr-2"/>
|
||||
Coordonnées GPS (optionnel)
|
||||
</span>
|
||||
</p:divider>
|
||||
</div>
|
||||
|
||||
<!-- Latitude -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="latitude" value="Latitude" />
|
||||
<p:inputNumber id="latitude"
|
||||
value="#{model.latitude}"
|
||||
<p:outputLabel for="latitude" value="Latitude" styleClass="font-semibold"/>
|
||||
<p:inputNumber id="latitude"
|
||||
value="#{model.latitude}"
|
||||
decimalPlaces="6"
|
||||
minValue="-90"
|
||||
maxValue="90"
|
||||
placeholder="Ex: 5.316667" />
|
||||
<small class="text-muted">Valeur entre -90 et 90</small>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-compass mr-1"/>
|
||||
Valeur entre -90 et 90 (ex: Abidjan ≈ 5.316667)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Longitude -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="longitude" value="Longitude" />
|
||||
<p:inputNumber id="longitude"
|
||||
value="#{model.longitude}"
|
||||
<p:outputLabel for="longitude" value="Longitude" styleClass="font-semibold"/>
|
||||
<p:inputNumber id="longitude"
|
||||
value="#{model.longitude}"
|
||||
decimalPlaces="6"
|
||||
minValue="-180"
|
||||
maxValue="180"
|
||||
placeholder="Ex: -4.033333" />
|
||||
<small class="text-muted">Valeur entre -180 et 180</small>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-compass mr-1"/>
|
||||
Valeur entre -180 et 180 (ex: Abidjan ≈ -4.033333)
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -247,63 +430,103 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 4 : STRUCTURE & HIÉRARCHIE -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Structure & Hiérarchie" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="🏢 Structure & Hiérarchie" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Statut juridique -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel value="Statut juridique" styleClass="font-semibold block mb-3" />
|
||||
<p:outputLabel value="Statut juridique" styleClass="font-semibold block mb-3">
|
||||
<i class="pi pi-building text-primary mr-2"/>
|
||||
</p:outputLabel>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-4">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="publique" value="#{model.organisationPublique}" />
|
||||
<p:outputLabel for="publique" value="Organisation publique" styleClass="ml-2" />
|
||||
<p:outputLabel for="publique" value="Organisation publique" styleClass="ml-2 font-semibold" />
|
||||
</div>
|
||||
<small class="text-muted block mt-1">Institution étatique ou gouvernementale</small>
|
||||
<small class="text-500 block mt-1">
|
||||
<i class="pi pi-shield mr-1"/>
|
||||
Institution étatique ou gouvernementale
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-4">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="accepteMembres" value="#{model.accepteNouveauxMembres}" />
|
||||
<p:outputLabel for="accepteMembres" value="Recrutement ouvert" styleClass="ml-2" />
|
||||
<p:outputLabel for="accepteMembres" value="Recrutement ouvert" styleClass="ml-2 font-semibold" />
|
||||
</div>
|
||||
<small class="text-muted block mt-1">Accepte de nouveaux membres</small>
|
||||
<small class="text-500 block mt-1">
|
||||
<i class="pi pi-user-plus mr-1"/>
|
||||
Accepte de nouveaux membres actuellement
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="field col-12 md:col-4">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="cotisationObl" value="#{model.cotisationObligatoire}" />
|
||||
<p:outputLabel for="cotisationObl" value="Cotisation obligatoire" styleClass="ml-2" />
|
||||
<p:outputLabel for="cotisationObl" value="Cotisation obligatoire" styleClass="ml-2 font-semibold" />
|
||||
</div>
|
||||
<small class="text-muted block mt-1">Adhésion payante requise</small>
|
||||
<small class="text-500 block mt-1">
|
||||
<i class="pi pi-money-bill mr-1"/>
|
||||
Adhésion payante requise pour les membres
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Séparateur visuel -->
|
||||
<div class="field col-12">
|
||||
<p:divider />
|
||||
<p:outputLabel value="Rattachement hiérarchique" styleClass="font-semibold block mb-3" />
|
||||
<p:divider styleClass="my-3">
|
||||
<span class="text-600 font-semibold">
|
||||
<i class="pi pi-sitemap mr-2"/>
|
||||
Rattachement hiérarchique
|
||||
</span>
|
||||
</p:divider>
|
||||
</div>
|
||||
|
||||
<!-- Organisation parente -->
|
||||
<div class="field col-12 md:col-9">
|
||||
<p:outputLabel for="orgParente" value="Organisation parente" styleClass="font-semibold" />
|
||||
<p:inputText id="orgParente"
|
||||
value="#{model.organisationParenteId}"
|
||||
maxlength="36"
|
||||
placeholder="Sélectionner ou saisir l'identifiant de l'organisation mère" />
|
||||
<small class="text-muted">Laisser vide si l'organisation est indépendante ou au sommet de la hiérarchie</small>
|
||||
<p:autoComplete id="orgParente"
|
||||
value="#{model.organisationParenteId}"
|
||||
completeMethod="#{completionBean.rechercherOrganisations}"
|
||||
var="org"
|
||||
itemLabel="#{org.nom}"
|
||||
itemValue="#{org.id}"
|
||||
placeholder="Rechercher une organisation parente..."
|
||||
minQueryLength="2"
|
||||
queryDelay="300"
|
||||
forceSelection="true"
|
||||
dropdown="true"
|
||||
scrollHeight="300"
|
||||
emptyMessage="Aucune organisation trouvée">
|
||||
<p:column headerText="Nom" style="width:60%">
|
||||
<h:outputText value="#{org.nom}" styleClass="font-semibold"/>
|
||||
</p:column>
|
||||
<p:column headerText="Type" style="width:40%">
|
||||
<h:outputText value="#{org.typeLibelle}" styleClass="text-500" />
|
||||
</p:column>
|
||||
</p:autoComplete>
|
||||
<p:message for="orgParente" />
|
||||
<p:tooltip for="orgParente" value="Recherchez et sélectionnez l'organisation mère si cette organisation est une sous-structure. Laissez vide si c'est une organisation racine." position="top"/>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-sitemap mr-1"/>
|
||||
Laisser vide si l'organisation est indépendante ou au sommet de la hiérarchie
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Niveau hiérarchique -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="niveau" value="Niveau" styleClass="font-semibold" />
|
||||
<p:inputNumber id="niveau"
|
||||
value="#{model.niveauHierarchique}"
|
||||
<p:outputLabel for="niveau" value="Niveau hiérarchique" styleClass="font-semibold" />
|
||||
<p:inputNumber id="niveau"
|
||||
value="#{model.niveauHierarchique}"
|
||||
decimalPlaces="0"
|
||||
minValue="0"
|
||||
maxValue="10"
|
||||
placeholder="0" />
|
||||
<small class="text-muted">0 = Niveau national/racine<br/>1 = Niveau régional<br/>2+ = Niveaux locaux</small>
|
||||
<small class="text-500">
|
||||
0 = National/Racine<br/>
|
||||
1 = Régional<br/>
|
||||
2+ = Niveaux locaux
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -311,26 +534,34 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 5 : MEMBRES & GOUVERNANCE -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Membres & Gouvernance" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="👥 Membres & Gouvernance" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Nombre de membres -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="nbMembres" value="Nombre de membres" styleClass="font-semibold" />
|
||||
<p:inputNumber id="nbMembres"
|
||||
value="#{model.nombreMembres}"
|
||||
<p:inputNumber id="nbMembres"
|
||||
value="#{model.nombreMembres}"
|
||||
decimalPlaces="0"
|
||||
minValue="0"
|
||||
placeholder="0" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-users mr-1"/>
|
||||
Nombre total de membres actifs de l'organisation
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Nombre d'administrateurs -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="nbAdmins" value="Nombre d'administrateurs" styleClass="font-semibold" />
|
||||
<p:inputNumber id="nbAdmins"
|
||||
value="#{model.nombreAdministrateurs}"
|
||||
<p:inputNumber id="nbAdmins"
|
||||
value="#{model.nombreAdministrateurs}"
|
||||
decimalPlaces="0"
|
||||
minValue="0"
|
||||
placeholder="0" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-user-edit mr-1"/>
|
||||
Nombre de membres du bureau exécutif ou du conseil d'administration
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -338,68 +569,114 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 6 : BUDGET & FINANCES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Budget & Finances" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="💰 Budget & Finances" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
|
||||
<!-- Devise — placée EN PREMIER pour piloter les décimales des champs montants -->
|
||||
<div class="field col-12 md:col-3">
|
||||
<p:outputLabel for="devise" value="Devise" styleClass="font-semibold" />
|
||||
<p:selectOneMenu id="devise"
|
||||
value="#{model.devise}">
|
||||
<!-- Devises africaines uniquement -->
|
||||
<!-- Franc CFA : pas de centimes (0 décimale) -->
|
||||
<f:selectItem itemLabel="XOF — Franc CFA (UEMOA)" itemValue="XOF" />
|
||||
<f:selectItem itemLabel="XAF — Franc CFA (CEMAC)" itemValue="XAF" />
|
||||
<!-- Afrique du Nord -->
|
||||
<f:selectItem itemLabel="MAD — Dirham marocain" itemValue="MAD" />
|
||||
<f:selectItem itemLabel="DZD — Dinar algérien" itemValue="DZD" />
|
||||
<f:selectItem itemLabel="TND — Dinar tunisien" itemValue="TND" />
|
||||
<!-- Autres devises africaines (2 décimales) -->
|
||||
<f:selectItem itemLabel="NGN — Naira nigérian" itemValue="NGN" />
|
||||
<f:selectItem itemLabel="GHS — Cedi ghanéen" itemValue="GHS" />
|
||||
<f:selectItem itemLabel="KES — Shilling kényan" itemValue="KES" />
|
||||
<f:selectItem itemLabel="ZAR — Rand sud-africain" itemValue="ZAR" />
|
||||
<p:ajax event="change" update="panelBudget panelCotisation" />
|
||||
</p:selectOneMenu>
|
||||
<p:tooltip for="devise" value="Code ISO 4217 de la devise (3 lettres)" position="top"/>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-info-circle mr-1"/>
|
||||
XOF/XAF (Franc CFA) : entiers, sans centimes
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Budget annuel -->
|
||||
<div class="field col-12 md:col-5">
|
||||
<p:outputLabel for="budget" value="Budget annuel" styleClass="font-semibold" />
|
||||
<p:inputNumber id="budget"
|
||||
value="#{model.budgetAnnuel}"
|
||||
decimalPlaces="2"
|
||||
minValue="0"
|
||||
placeholder="0.00" />
|
||||
</div>
|
||||
|
||||
<!-- Devise -->
|
||||
<div class="field col-12 md:col-2">
|
||||
<p:outputLabel for="devise" value="Devise" styleClass="font-semibold" />
|
||||
<p:inputText id="devise"
|
||||
value="#{model.devise}"
|
||||
maxlength="3"
|
||||
placeholder="XOF"
|
||||
style="text-transform: uppercase;" />
|
||||
<small class="text-muted">Code ISO (ex: XOF, EUR)</small>
|
||||
<h:panelGroup id="panelBudget" layout="block">
|
||||
<p:inputNumber id="budget"
|
||||
value="#{model.budgetAnnuel}"
|
||||
decimalPlaces="#{model.devise == 'XOF' or model.devise == 'XAF' ? 0 : 2}"
|
||||
minValue="0"
|
||||
placeholder="#{model.devise == 'XOF' or model.devise == 'XAF' ? '0' : '0,00'}"
|
||||
decimalSeparator=","
|
||||
thousandSeparator=" " />
|
||||
</h:panelGroup>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-chart-line mr-1"/>
|
||||
Budget prévisionnel ou réalisé de l'année en cours
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Montant cotisation -->
|
||||
<div class="field col-12 md:col-5">
|
||||
<p:outputLabel for="montantCotisation" value="Cotisation annuelle" styleClass="font-semibold" />
|
||||
<p:inputNumber id="montantCotisation"
|
||||
value="#{model.montantCotisationAnnuelle}"
|
||||
decimalPlaces="2"
|
||||
minValue="0"
|
||||
placeholder="0.00" />
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="montantCotisation" value="Cotisation annuelle (membre)" styleClass="font-semibold" />
|
||||
<h:panelGroup id="panelCotisation" layout="block">
|
||||
<p:inputNumber id="montantCotisation"
|
||||
value="#{model.montantCotisationAnnuelle}"
|
||||
decimalPlaces="#{model.devise == 'XOF' or model.devise == 'XAF' ? 0 : 2}"
|
||||
minValue="0"
|
||||
placeholder="#{model.devise == 'XOF' or model.devise == 'XAF' ? '0' : '0,00'}"
|
||||
decimalSeparator=","
|
||||
thousandSeparator=" " />
|
||||
</h:panelGroup>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-wallet mr-1"/>
|
||||
Montant annuel de la cotisation par membre (si applicable)
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</p:fieldset>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 7 : MISSION & ACTIVITÉS -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Mission & Activités" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="🎯 Mission & Activités" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Objectifs -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="objectifs" value="Objectifs stratégiques" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="objectifs"
|
||||
value="#{model.objectifs}"
|
||||
rows="4"
|
||||
<p:inputTextarea id="objectifs"
|
||||
value="#{model.objectifs}"
|
||||
rows="4"
|
||||
maxlength="2000"
|
||||
placeholder="Décrivez les objectifs principaux de l'organisation..."
|
||||
autoResize="false" />
|
||||
<small class="text-muted">#{2000 - (empty model.objectifs ? 0 : model.objectifs.length())} caractères restants</small>
|
||||
placeholder="Décrivez les objectifs principaux de l'organisation, sa vision et ses buts stratégiques..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="2000" />
|
||||
</p:inputTextarea>
|
||||
<p:message for="objectifs" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-flag mr-1"/>
|
||||
Maximum 2000 caractères
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Activités principales -->
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="activites" value="Activités principales" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="activites"
|
||||
value="#{model.activitesPrincipales}"
|
||||
rows="4"
|
||||
<p:inputTextarea id="activites"
|
||||
value="#{model.activitesPrincipales}"
|
||||
rows="4"
|
||||
maxlength="2000"
|
||||
placeholder="Décrivez les activités et programmes mis en œuvre..."
|
||||
autoResize="false" />
|
||||
<small class="text-muted">#{2000 - (empty model.activitesPrincipales ? 0 : model.activitesPrincipales.length())} caractères restants</small>
|
||||
placeholder="Décrivez les activités, programmes et initiatives concrètes mis en œuvre par l'organisation..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="2000" />
|
||||
</p:inputTextarea>
|
||||
<p:message for="activites" />
|
||||
<small class="text-500">
|
||||
<i class="pi pi-list mr-1"/>
|
||||
Maximum 2000 caractères
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -407,28 +684,40 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 8 : PARTENARIATS & CERTIFICATIONS -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Partenariats & Certifications" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="🤝 Partenariats & Certifications" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<!-- Certifications / Labels -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="certifications" value="Certifications / Labels" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="certifications"
|
||||
value="#{model.certifications}"
|
||||
rows="3"
|
||||
<p:inputTextarea id="certifications"
|
||||
value="#{model.certifications}"
|
||||
rows="3"
|
||||
maxlength="500"
|
||||
placeholder="Ex: ISO 9001, Label RSE..."
|
||||
autoResize="false" />
|
||||
placeholder="Ex: ISO 9001:2015, Label RSE, Certification Qualité..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="500" />
|
||||
</p:inputTextarea>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-verified mr-1"/>
|
||||
Maximum 500 caractères
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Partenaires principaux -->
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="partenaires" value="Partenaires principaux" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="partenaires"
|
||||
value="#{model.partenaires}"
|
||||
rows="3"
|
||||
<p:inputTextarea id="partenaires"
|
||||
value="#{model.partenaires}"
|
||||
rows="3"
|
||||
maxlength="1000"
|
||||
placeholder="Liste des partenaires stratégiques..."
|
||||
autoResize="false" />
|
||||
placeholder="Liste des partenaires stratégiques, bailleurs, organisations partenaires..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="1000" />
|
||||
</p:inputTextarea>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-users mr-1"/>
|
||||
Maximum 1000 caractères
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
@@ -436,21 +725,26 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<!-- SECTION 9 : NOTES ADMINISTRATIVES -->
|
||||
<!-- ═══════════════════════════════════════════════════════════════ -->
|
||||
<p:fieldset legend="Notes administratives" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<p:fieldset legend="📝 Notes administratives" toggleable="true" collapsed="true" styleClass="mb-3">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="notes" value="Notes internes" styleClass="font-semibold" />
|
||||
<p:inputTextarea id="notes"
|
||||
value="#{model.notes}"
|
||||
rows="4"
|
||||
<p:inputTextarea id="notes"
|
||||
value="#{model.notes}"
|
||||
rows="4"
|
||||
maxlength="1000"
|
||||
placeholder="Notes réservées à l'usage administratif interne..."
|
||||
autoResize="false" />
|
||||
<small class="text-muted">Ces notes ne sont visibles que par les administrateurs</small>
|
||||
placeholder="Notes réservées à l'usage administratif interne, remarques, historique..."
|
||||
autoResize="false">
|
||||
<f:validateLength maximum="1000" />
|
||||
</p:inputTextarea>
|
||||
<small class="text-500">
|
||||
<i class="pi pi-lock mr-1"/>
|
||||
Ces notes ne sont visibles que par les administrateurs - Maximum 1000 caractères
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</p:fieldset>
|
||||
|
||||
</div>
|
||||
|
||||
</ui:fragment>
|
||||
</ui:fragment>
|
||||
|
||||
@@ -7,21 +7,32 @@ quarkus.log.category."jakarta.faces".level=INFO
|
||||
quarkus.log.category."org.apache.myfaces".level=INFO
|
||||
quarkus.log.category."org.primefaces".level=INFO
|
||||
|
||||
# Configuration MyFaces pour développement
|
||||
quarkus.myfaces.project-stage=Development
|
||||
# Hot reload
|
||||
quarkus.live-reload.instrumentation=true
|
||||
|
||||
# Configuration Keycloak pour développement
|
||||
# Configuration Keycloak pour développement LOCAL
|
||||
%dev.quarkus.oidc.enabled=true
|
||||
%dev.quarkus.oidc.tls.verification=none
|
||||
%dev.quarkus.oidc.authentication.redirect-path=/auth/callback
|
||||
# %dev.quarkus.oidc.authentication.force-redirect-https=false # Not supported in this Quarkus version
|
||||
%dev.quarkus.security.auth.enabled=true
|
||||
|
||||
# Secret Keycloak pour développement (UNIQUEMENT pour dev local)
|
||||
# ⚠️ ATTENTION: Ne jamais commiter ce secret en production
|
||||
# En production, utiliser la variable d'environnement KEYCLOAK_CLIENT_SECRET
|
||||
%dev.quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET:7dnWMwlabtoyp08F6FIuDxzDPE5VdUF6}
|
||||
# Configuration pour Keycloak local sur http://localhost:8180
|
||||
%dev.quarkus.oidc.auth-server-url=http://localhost:8180/realms/unionflow
|
||||
%dev.quarkus.oidc.client-id=unionflow-client
|
||||
|
||||
# SÉCURITÉ: TLS verification désactivée UNIQUEMENT pour Keycloak local HTTP
|
||||
# En production, toujours utiliser HTTPS avec tls.verification=required
|
||||
%dev.quarkus.oidc.tls.verification=none
|
||||
|
||||
%dev.quarkus.oidc.authentication.redirect-path=/auth/callback
|
||||
%dev.quarkus.oidc.authentication.restore-path-after-redirect=true
|
||||
%dev.quarkus.oidc.authentication.scopes=openid,profile,email,roles
|
||||
%dev.quarkus.oidc.token.issuer=any
|
||||
|
||||
# Secret Keycloak pour développement
|
||||
# SÉCURITÉ: En dev local, on peut utiliser un secret par défaut pour faciliter le développement
|
||||
# En production, utilisez TOUJOURS une variable d'environnement
|
||||
%dev.quarkus.oidc.credentials.secret=P18Mw0uNVzSPeI4P0fymD18r2oxiejw4
|
||||
|
||||
# Configuration Backend pour dev local
|
||||
%dev.unionflow.backend.url=http://localhost:8085
|
||||
|
||||
# Logging OIDC pour debug
|
||||
%dev.quarkus.log.category."io.quarkus.oidc".level=DEBUG
|
||||
|
||||
@@ -9,11 +9,41 @@ quarkus.http.so-reuse-port=true
|
||||
quarkus.http.tcp-quick-ack=true
|
||||
quarkus.http.tcp-cork=true
|
||||
|
||||
# Configuration Session HTTP - Production
|
||||
quarkus.http.session-timeout=60m
|
||||
quarkus.http.session-cookie-same-site=strict
|
||||
quarkus.http.session-cookie-http-only=true
|
||||
quarkus.http.session-cookie-secure=true
|
||||
# ===================================================================================================
|
||||
# Headers de Sécurité HTTP - PRODUCTION
|
||||
# ===================================================================================================
|
||||
# Prévention du MIME sniffing
|
||||
quarkus.http.header."X-Content-Type-Options".value=nosniff
|
||||
quarkus.http.header."X-Content-Type-Options".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Protection contre le clickjacking
|
||||
quarkus.http.header."X-Frame-Options".value=DENY
|
||||
quarkus.http.header."X-Frame-Options".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# HSTS - Force HTTPS pour 1 an
|
||||
quarkus.http.header."Strict-Transport-Security".value=max-age=31536000; includeSubDomains; preload
|
||||
quarkus.http.header."Strict-Transport-Security".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Content Security Policy
|
||||
# Permet 'unsafe-inline' pour PrimeFaces/JSF qui génèrent des scripts inline
|
||||
quarkus.http.header."Content-Security-Policy".value=default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'
|
||||
quarkus.http.header."Content-Security-Policy".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Protection XSS (legacy, mais utile pour anciens navigateurs)
|
||||
quarkus.http.header."X-XSS-Protection".value=1; mode=block
|
||||
quarkus.http.header."X-XSS-Protection".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Politique de référents
|
||||
quarkus.http.header."Referrer-Policy".value=strict-origin-when-cross-origin
|
||||
quarkus.http.header."Referrer-Policy".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Permissions Policy (anciennement Feature-Policy)
|
||||
quarkus.http.header."Permissions-Policy".value=geolocation=(), microphone=(), camera=()
|
||||
quarkus.http.header."Permissions-Policy".methods=GET,POST,PUT,DELETE,PATCH
|
||||
|
||||
# Compression HTTP pour améliorer les performances
|
||||
quarkus.http.enable-compression=true
|
||||
quarkus.http.compression-level=6
|
||||
|
||||
# Configuration logging - Production
|
||||
quarkus.log.console.enable=true
|
||||
@@ -23,35 +53,6 @@ quarkus.log.category."dev.lions.unionflow".level=INFO
|
||||
quarkus.log.category."org.primefaces".level=WARN
|
||||
quarkus.log.category."org.apache.myfaces".level=WARN
|
||||
|
||||
# MyFaces Configuration - Production
|
||||
quarkus.myfaces.project-stage=Production
|
||||
quarkus.myfaces.state-saving-method=server
|
||||
quarkus.myfaces.number-of-views-in-session=50
|
||||
quarkus.myfaces.number-of-sequential-views-in-session=10
|
||||
quarkus.myfaces.serialize-state-in-session=false
|
||||
quarkus.myfaces.client-view-state-timeout=3600000
|
||||
quarkus.myfaces.view-expired-exception-handler-redirect-page=/
|
||||
quarkus.myfaces.check-id-production-mode=true
|
||||
quarkus.myfaces.strict-xhtml-links=true
|
||||
quarkus.myfaces.refresh-transient-build-on-pss=true
|
||||
quarkus.myfaces.resource-max-time-expires=604800000
|
||||
quarkus.myfaces.resource-buffer-size=2048
|
||||
|
||||
# PrimeFaces Configuration - Production
|
||||
primefaces.THEME=none
|
||||
primefaces.FONT_AWESOME=true
|
||||
primefaces.CLIENT_SIDE_VALIDATION=true
|
||||
primefaces.MOVE_SCRIPTS_TO_BOTTOM=true
|
||||
primefaces.CSP=true
|
||||
primefaces.UPLOADER=commons
|
||||
primefaces.AUTO_UPDATE=false
|
||||
primefaces.CACHE_PROVIDER=org.primefaces.cache.DefaultCacheProvider
|
||||
primefaces.RESOURCE_HANDLER=org.primefaces.application.resource.PrimeResourceHandler
|
||||
|
||||
# OmniFaces Configuration - Production
|
||||
omnifaces.CDN_RESOURCE_HANDLER_DISABLED=true
|
||||
omnifaces.COMBINED_RESOURCE_HANDLER_DISABLED=false
|
||||
|
||||
# Configuration Backend UnionFlow - Production
|
||||
unionflow.backend.url=${UNIONFLOW_BACKEND_URL:https://api.lions.dev/unionflow}
|
||||
|
||||
@@ -59,8 +60,9 @@ unionflow.backend.url=${UNIONFLOW_BACKEND_URL:https://api.lions.dev/unionflow}
|
||||
quarkus.rest-client."unionflow-api".url=${unionflow.backend.url}
|
||||
quarkus.rest-client."unionflow-api".scope=jakarta.inject.Singleton
|
||||
quarkus.rest-client."unionflow-api".connect-timeout=5000
|
||||
quarkus.rest-client."unionflow-api".read-timeout=30000
|
||||
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper,dev.lions.unionflow.client.security.JwtClientRequestFilter
|
||||
quarkus.rest-client."unionflow-api".read-timeout=15000
|
||||
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper
|
||||
# NOTE: JwtClientRequestFilter retiré - utilisation de AuthHeaderFactory via @RegisterClientHeaders
|
||||
|
||||
# Configuration Keycloak OIDC - Production
|
||||
quarkus.oidc.enabled=true
|
||||
@@ -68,35 +70,50 @@ quarkus.oidc.auth-server-url=${KEYCLOAK_AUTH_SERVER_URL:https://security.lions.d
|
||||
quarkus.oidc.client-id=unionflow-client
|
||||
quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET}
|
||||
quarkus.oidc.application-type=web-app
|
||||
# Callback path - must match Keycloak Valid Redirect URIs configuration
|
||||
quarkus.oidc.authentication.redirect-path=/auth/callback
|
||||
quarkus.oidc.authentication.force-redirect-https-scheme=true
|
||||
quarkus.oidc.authentication.restore-path-after-redirect=true
|
||||
# Default landing page after successful login
|
||||
quarkus.oidc.authentication.scopes=openid,profile,email,roles
|
||||
quarkus.oidc.token.issuer=https://security.lions.dev/realms/unionflow
|
||||
quarkus.oidc.tls.verification=required
|
||||
quarkus.oidc.authentication.cookie-same-site=lax
|
||||
quarkus.oidc.authentication.java-script-auto-redirect=false
|
||||
quarkus.oidc.discovery-enabled=true
|
||||
quarkus.oidc.verify-access-token=true
|
||||
|
||||
# Activation de la sécurité
|
||||
quarkus.security.auth.enabled=true
|
||||
|
||||
# IMPORTANT: L'ordre des permissions compte - les plus spécifiques doivent être EN PREMIER
|
||||
# Chemins publics (non protégés par OIDC) - Production
|
||||
quarkus.http.auth.permission.public.paths=/,/index.xhtml,/pages/public/*,/auth/*,/q/*,/q/oidc/*,/favicon.ico,/resources/*,/META-INF/resources/*,/images/*,/jakarta.faces.resource/*,/javax.faces.resource/*
|
||||
quarkus.http.auth.permission.public.policy=permit
|
||||
|
||||
# Tous les autres chemins nécessitent une authentification
|
||||
quarkus.http.auth.permission.authenticated.paths=/*
|
||||
quarkus.http.auth.permission.authenticated.paths=/pages/secure/*
|
||||
quarkus.http.auth.permission.authenticated.policy=authenticated
|
||||
|
||||
# Configuration Session - Production
|
||||
# Configuration Session (custom properties, gérées côté applicatif)
|
||||
unionflow.session.timeout=${SESSION_TIMEOUT:1800}
|
||||
unionflow.session.remember-me.duration=${REMEMBER_ME_DURATION:604800}
|
||||
|
||||
# Configuration de sécurité - Production
|
||||
# Configuration de sécurité (custom properties, gérées côté applicatif)
|
||||
unionflow.security.enable-csrf=${ENABLE_CSRF:true}
|
||||
unionflow.security.password.min-length=${PASSWORD_MIN_LENGTH:8}
|
||||
unionflow.security.password.require-special-chars=${PASSWORD_REQUIRE_SPECIAL:true}
|
||||
unionflow.security.max-login-attempts=${MAX_LOGIN_ATTEMPTS:5}
|
||||
unionflow.security.lockout-duration=${LOCKOUT_DURATION:300}
|
||||
|
||||
# ===================================================================================================
|
||||
# Configuration Quarkus Arc CDI - Intégration avec JSF/MyFaces - Production
|
||||
# ===================================================================================================
|
||||
# Active le mode découverte de beans pour permettre à Arc de gérer tous les beans CDI et JSF
|
||||
quarkus.arc.unremovable-types=jakarta.faces.application.Application,jakarta.faces.context.FacesContext,jakarta.enterprise.context.Conversation
|
||||
|
||||
# Permet à Arc de détecter et gérer les beans avec annotations JSF custom scopes (@ViewScoped, etc.)
|
||||
quarkus.arc.detect-unused-false-positives=true
|
||||
|
||||
# Force Arc à gérer les beans même s'ils ne sont pas référencés directement
|
||||
quarkus.arc.remove-unused-beans=false
|
||||
|
||||
# Active le support complet CDI pour JSF Expression Language (EL)
|
||||
# Cela permet à MyFaces d'utiliser Arc BeanManager pour résoudre #{bean.property}
|
||||
quarkus.arc.auto-inject-fields=true
|
||||
|
||||
@@ -10,48 +10,11 @@ quarkus.http.so-reuse-port=true
|
||||
quarkus.http.tcp-quick-ack=true
|
||||
quarkus.http.tcp-cork=true
|
||||
|
||||
# Configuration Session HTTP
|
||||
quarkus.http.session-timeout=60m
|
||||
quarkus.http.session-cookie-same-site=lax
|
||||
quarkus.http.session-cookie-http-only=true
|
||||
quarkus.http.session-cookie-secure=false
|
||||
|
||||
# Configuration logging
|
||||
quarkus.log.console.enable=true
|
||||
quarkus.log.console.level=INFO
|
||||
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{2.}] (%t) %s%e%n
|
||||
|
||||
# MyFaces Configuration
|
||||
quarkus.myfaces.project-stage=Development
|
||||
quarkus.myfaces.state-saving-method=server
|
||||
quarkus.myfaces.number-of-views-in-session=50
|
||||
quarkus.myfaces.number-of-sequential-views-in-session=10
|
||||
quarkus.myfaces.serialize-state-in-session=false
|
||||
quarkus.myfaces.client-view-state-timeout=3600000
|
||||
quarkus.myfaces.view-expired-exception-handler-redirect-page=/
|
||||
quarkus.myfaces.check-id-production-mode=false
|
||||
quarkus.myfaces.strict-xhtml-links=false
|
||||
quarkus.myfaces.refresh-transient-build-on-pss=true
|
||||
quarkus.myfaces.resource-max-time-expires=604800000
|
||||
quarkus.myfaces.resource-buffer-size=2048
|
||||
|
||||
# PrimeFaces Configuration
|
||||
# IMPORTANT: Nous laissons PrimeFaces sans th<74>me par d<>faut et chargeons le th<74>me Freya via index.xhtml/main-template.xhtml
|
||||
# pour <20>viter tout double-chargement (ex: Saga + Freya).
|
||||
primefaces.THEME=none
|
||||
primefaces.FONT_AWESOME=true
|
||||
primefaces.CLIENT_SIDE_VALIDATION=true
|
||||
primefaces.MOVE_SCRIPTS_TO_BOTTOM=true
|
||||
primefaces.CSP=false
|
||||
primefaces.UPLOADER=commons
|
||||
primefaces.AUTO_UPDATE=false
|
||||
primefaces.CACHE_PROVIDER=org.primefaces.cache.DefaultCacheProvider
|
||||
primefaces.RESOURCE_HANDLER=org.primefaces.application.resource.PrimeResourceHandler
|
||||
|
||||
# OmniFaces Configuration
|
||||
omnifaces.CDN_RESOURCE_HANDLER_DISABLED=true
|
||||
omnifaces.COMBINED_RESOURCE_HANDLER_DISABLED=false
|
||||
|
||||
# Configuration Backend UnionFlow
|
||||
unionflow.backend.url=${UNIONFLOW_BACKEND_URL:http://localhost:8085}
|
||||
|
||||
@@ -61,8 +24,8 @@ quarkus.rest-client."unionflow-api".scope=jakarta.inject.Singleton
|
||||
quarkus.rest-client."unionflow-api".connect-timeout=5000
|
||||
quarkus.rest-client."unionflow-api".read-timeout=30000
|
||||
|
||||
# Gestion des erreurs REST + propagation JWT vers le backend
|
||||
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper,dev.lions.unionflow.client.security.JwtClientRequestFilter
|
||||
# Gestion des erreurs REST (JwtClientRequestFilter est déprécié - remplacé par AuthHeaderFactory)
|
||||
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper
|
||||
|
||||
# Configuration Keycloak OIDC
|
||||
quarkus.oidc.enabled=true
|
||||
@@ -74,28 +37,22 @@ quarkus.oidc.authentication.redirect-path=/auth/callback
|
||||
quarkus.oidc.authentication.restore-path-after-redirect=true
|
||||
quarkus.oidc.authentication.scopes=openid,profile,email,roles
|
||||
quarkus.oidc.token.issuer=https://security.lions.dev/realms/unionflow
|
||||
quarkus.oidc.tls.verification=none
|
||||
# quarkus.oidc.authentication.force-redirect-https=false # Not supported in this Quarkus version
|
||||
# SÉCURITÉ: TLS verification DOIT être 'required' par défaut
|
||||
# Seulement 'none' en développement local (voir application-dev.properties)
|
||||
quarkus.oidc.tls.verification=required
|
||||
quarkus.oidc.authentication.cookie-same-site=lax
|
||||
quarkus.oidc.authentication.java-script-auto-redirect=false
|
||||
quarkus.oidc.discovery-enabled=true
|
||||
|
||||
# TEMPORAIRE: contourner un access token invalide (claim realm_access dupliqu<71>e c<>t<EFBFBD> KC)
|
||||
# Pour un flux web-app, on peut s'appuyer sur l'ID Token et d<>sactiver la v<>rification de l'Access Token
|
||||
# Les deux cl<63>s ci?dessous couvrent les variantes selon version de Quarkus; l'une sera ignor<6F>e si non support<72>e.
|
||||
# Vérification du token activée
|
||||
# ✅ CORRIGÉ: Le mapper Keycloak problématique a été supprimé (17/11/2025)
|
||||
# Le scope "roles" gère maintenant correctement realm_access.roles (objet unique)
|
||||
quarkus.oidc.verify-access-token=true
|
||||
# Configuration du logout OIDC
|
||||
quarkus.oidc.logout.path=/logout
|
||||
quarkus.oidc.logout.post-logout-path=/index.xhtml
|
||||
|
||||
# Activation de la sécurité
|
||||
quarkus.security.auth.enabled=true
|
||||
|
||||
# Chemins publics (non prot<6F>g<EFBFBD>s par OIDC) - Doit <20>tre d<>fini en premier
|
||||
# Chemins publics (non protégés par OIDC) - Doit être défini en premier
|
||||
# La page d'accueil (/) et index.xhtml sont publics pour permettre l'affichage initial
|
||||
# IMPORTANT: Les ressources JSF/PrimeFaces sont servies via /jakarta.faces.resource/* (ou /javax.faces.resource/* selon la stack)
|
||||
# Elles doivent <EFBFBD>tre publiques pour permettre le chargement des CSS/JS (th<EFBFBD>me Freya, primeicons, primeflex, etc.)
|
||||
# On inclut <EFBFBD>galement /q/oidc/* pour laisser Quarkus OIDC exposer ses endpoints internes si n<EFBFBD>cessaire.
|
||||
# Elles doivent être publiques pour permettre le chargement des CSS/JS (thème Freya, primeicons, primeflex, etc.)
|
||||
# On inclut également /q/oidc/* pour laisser Quarkus OIDC exposer ses endpoints internes si nécessaire.
|
||||
quarkus.http.auth.permission.public.paths=/,/index.xhtml,/pages/public/*,/auth/*,/q/*,/q/oidc/*,/favicon.ico,/resources/*,/META-INF/resources/*,/images/*,/jakarta.faces.resource/*,/javax.faces.resource/*
|
||||
quarkus.http.auth.permission.public.policy=permit
|
||||
|
||||
@@ -105,11 +62,11 @@ quarkus.http.auth.permission.public.policy=permit
|
||||
quarkus.http.auth.permission.authenticated.paths=/*
|
||||
quarkus.http.auth.permission.authenticated.policy=authenticated
|
||||
|
||||
# Configuration Session
|
||||
# Configuration Session (custom properties, gérées côté applicatif)
|
||||
unionflow.session.timeout=${SESSION_TIMEOUT:1800}
|
||||
unionflow.session.remember-me.duration=${REMEMBER_ME_DURATION:604800}
|
||||
|
||||
# Configuration de sécurité
|
||||
# Configuration de sécurité (custom properties, gérées côté applicatif)
|
||||
unionflow.security.enable-csrf=${ENABLE_CSRF:true}
|
||||
unionflow.security.password.min-length=${PASSWORD_MIN_LENGTH:8}
|
||||
unionflow.security.password.require-special-chars=${PASSWORD_REQUIRE_SPECIAL:true}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user