Files

398 lines
27 KiB
HTML

<!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>