dcb-backoffice/src/app/modules/hub-users-management/hub-users-list/hub-users-list.html

429 lines
16 KiB
HTML

<app-ui-card [title]="'Liste des Utilisateurs Hub'">
<a
helper-text
href="javascript:void(0);"
class="icon-link icon-link-hover link-primary fw-semibold"
>
<ng-icon name="lucideUsers" class="me-1"></ng-icon>
Gérez les accès utilisateurs de votre plateforme DCB
</a>
<div card-body>
<!-- Indicateur de contexte pour la vue admin -->
@if (isAdminView) {
<div class="row mb-3">
<div class="col-12">
<div class="alert alert-warning">
<div class="d-flex align-items-center">
<ng-icon name="lucideShield" class="me-2"></ng-icon>
<div>
<strong>Vue Administrative Globale :</strong> Vous visualisez tous les utilisateurs Hub et Merchant de la plateforme
@if (showStatistics) {
<br>
<small class="text-muted">
{{ getHubUsersCount() }} utilisateurs Hub •
{{ getMerchantUsersCount() }} utilisateurs Merchant •
{{ getTotalUsersCountAdmin() }} total
</small>
}
</div>
</div>
</div>
</div>
</div>
}
<!-- Barre d'actions supérieure -->
<div class="row mb-3">
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<!-- Statistiques rapides -->
<div class="btn-group btn-group-sm">
<button
type="button"
class="btn btn-outline-primary"
[class.active]="roleFilter === 'all'"
(click)="filterByRole('all')"
>
Tous ({{ getTotalUsersCount() }})
</button>
<!-- Boutons pour VUE ADMIN (Hub + Merchant) -->
@if (isAdminView) {
<button
type="button"
class="btn btn-outline-danger"
[class.active]="roleFilter === UserRole.DCB_ADMIN"
(click)="filterByRole(UserRole.DCB_ADMIN)"
>
DCB Admins ({{ getUsersCountByRole(UserRole.DCB_ADMIN) }})
</button>
<button
type="button"
class="btn btn-outline-info"
[class.active]="roleFilter === UserRole.DCB_SUPPORT"
(click)="filterByRole(UserRole.DCB_SUPPORT)"
>
DCB Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
</button>
<button
type="button"
class="btn btn-outline-warning text-dark"
[class.active]="roleFilter === UserRole.DCB_PARTNER_ADMIN"
(click)="filterByRole(UserRole.DCB_PARTNER_ADMIN)"
>
Partner Admins ({{ getUsersCountByRole(UserRole.DCB_PARTNER_ADMIN) }})
</button>
<button
type="button"
class="btn btn-outline-secondary"
[class.active]="roleFilter === UserRole.DCB_PARTNER_MANAGER"
(click)="filterByRole(UserRole.DCB_PARTNER_MANAGER)"
>
Partner Managers ({{ getUsersCountByRole(UserRole.DCB_PARTNER_MANAGER) }})
</button>
<button
type="button"
class="btn btn-outline-dark"
[class.active]="roleFilter === UserRole.DCB_PARTNER_SUPPORT"
(click)="filterByRole(UserRole.DCB_PARTNER_SUPPORT)"
>
Partner Support ({{ getUsersCountByRole(UserRole.DCB_PARTNER_SUPPORT) }})
</button>
} @else {
<!-- Boutons pour VUE NORMALE HUB -->
<button
type="button"
class="btn btn-outline-danger"
[class.active]="roleFilter === UserRole.DCB_ADMIN"
(click)="filterByRole(UserRole.DCB_ADMIN)"
>
Admins ({{ getUsersCountByRole(UserRole.DCB_ADMIN) }})
</button>
<button
type="button"
class="btn btn-outline-info"
[class.active]="roleFilter === UserRole.DCB_SUPPORT"
(click)="filterByRole(UserRole.DCB_SUPPORT)"
>
Support ({{ getUsersCountByRole(UserRole.DCB_SUPPORT) }})
</button>
}
</div>
<!-- Filtre par contexte (uniquement vue admin) -->
@if (isAdminView) {
<div class="ms-2">
<select class="form-select form-select-sm" [(ngModel)]="contextFilter" (change)="applyFiltersAndPagination()">
<option value="all">Tous les contextes</option>
<option value="hub">Hub seulement</option>
<option value="merchant">Merchant seulement</option>
</select>
</div>
}
</div>
</div>
<div class="col-md-6">
<div class="d-flex justify-content-end gap-2">
@if (showCreateButton) {
<button
class="btn btn-primary"
(click)="openCreateUserModal.emit()"
>
<ng-icon name="lucideUserPlus" class="me-1"></ng-icon>
Nouvel Utilisateur Hub
</button>
}
<button
class="btn btn-outline-secondary"
(click)="refreshData()"
[disabled]="loading"
>
<ng-icon name="lucideRefreshCw" class="me-1" [class.spin]="loading"></ng-icon>
Actualiser
</button>
</div>
</div>
</div>
<!-- Barre de recherche et filtres avancés -->
<div class="row mb-3">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">
<ng-icon name="lucideSearch"></ng-icon>
</span>
<input
type="text"
class="form-control"
placeholder="Rechercher par nom, email..."
[(ngModel)]="searchTerm"
(input)="onSearch()"
[disabled]="loading"
>
</div>
</div>
<div class="col-md-2">
<select class="form-select" [(ngModel)]="statusFilter" (change)="applyFiltersAndPagination()">
<option value="all">Tous les statuts</option>
<option value="enabled">Activés seulement</option>
<option value="disabled">Désactivés seulement</option>
</select>
</div>
<div class="col-md-2">
<select class="form-select" [(ngModel)]="emailVerifiedFilter" (change)="applyFiltersAndPagination()">
<option value="all">Tous les emails</option>
<option value="verified">Email vérifié</option>
<option value="not-verified">Email non vérifié</option>
</select>
</div>
<div class="col-md-2">
<select class="form-select" [(ngModel)]="roleFilter" (change)="applyFiltersAndPagination()">
<option value="all">Tous les rôles</option>
@for (role of availableRoles; track role.value) {
<option [value]="role.value">{{ role.label }}</option>
}
</select>
</div>
<div class="col-md-2">
<button class="btn btn-outline-secondary w-100" (click)="onClearFilters()" [disabled]="loading">
<ng-icon name="lucideX" class="me-1"></ng-icon>
Effacer
</button>
</div>
</div>
<!-- Loading State -->
@if (loading) {
<div class="text-center py-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Chargement...</span>
</div>
<p class="mt-2 text-muted">Chargement des utilisateurs...</p>
</div>
}
<!-- Error State -->
@if (error && !loading) {
<div class="alert alert-danger" role="alert">
<div class="d-flex align-items-center">
<ng-icon name="lucideAlertCircle" class="me-2"></ng-icon>
<div>{{ error }}</div>
<button class="btn-close ms-auto" (click)="error = ''"></button>
</div>
</div>
}
<!-- Users Table -->
@if (!loading && !error) {
<div class="table-responsive">
<table class="table table-hover table-striped">
<thead class="table-light">
<tr>
<!-- Colonne Type d'utilisateur pour la vue admin -->
@if (showUserTypeColumn()) {
<th>Type</th>
}
<th (click)="sort('username')" class="cursor-pointer">
<div class="d-flex align-items-center">
<span>Utilisateur</span>
<ng-icon [name]="getSortIcon('username')" class="ms-1 fs-12"></ng-icon>
</div>
</th>
<th (click)="sort('email')" class="cursor-pointer">
<div class="d-flex align-items-center">
<span>Email</span>
<ng-icon [name]="getSortIcon('email')" class="ms-1 fs-12"></ng-icon>
</div>
</th>
<th>Rôle Principal</th>
<th (click)="sort('enabled')" class="cursor-pointer">
<div class="d-flex align-items-center">
<span>Statut</span>
<ng-icon [name]="getSortIcon('enabled')" class="ms-1 fs-12"></ng-icon>
</div>
</th>
<th (click)="sort('createdTimestamp')" class="cursor-pointer">
<div class="d-flex align-items-center">
<span>Créé le</span>
<ng-icon [name]="getSortIcon('createdTimestamp')" class="ms-1 fs-12"></ng-icon>
</div>
</th>
<th width="180">Actions</th>
</tr>
</thead>
<tbody>
@for (user of displayedUsers; track user.id) {
<tr>
<!-- Colonne Type d'utilisateur pour la vue admin -->
@if (showUserTypeColumn()) {
<td>
<span class="badge" [ngClass]="user.userType === UserType.HUB ? 'bg-primary' : 'bg-success'">
{{ user.userType === UserType.HUB ? 'Hub' : 'Merchant' }}
</span>
</td>
}
<td>
<div class="d-flex align-items-center">
<div class="avatar-sm bg-primary bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center me-2">
<span class="text-primary fw-semibold small">
{{ getUserInitials(user) }}
</span>
</div>
<div>
<strong class="d-block">{{ getUserDisplayName(user) }}</strong>
<small class="text-muted">@{{ user.username }}</small>
</div>
</div>
</td>
<td>
<div class="d-flex align-items-center">
{{ user.email }}
@if (!user.emailVerified) {
<ng-icon
name="lucideAlertTriangle"
class="ms-1 text-warning"
size="16"
title="Email non vérifié"
></ng-icon>
}
</div>
</td>
<td>
<span class="badge d-flex align-items-center" [ngClass]="getRoleBadgeClass(user.role)">
<ng-icon [name]="getRoleIcon(user.role)" class="me-1" size="14"></ng-icon>
{{ getRoleLabel(user.role) }}
</span>
</td>
<td>
<span [class]="getStatusBadgeClass(user)">
{{ getStatusText(user) }}
</span>
</td>
<td>
<small class="text-muted">
{{ formatTimestamp(user.createdTimestamp) }}
</small>
</td>
<td>
<div class="btn-group btn-group-sm" role="group">
<button
class="btn btn-outline-primary btn-sm"
(click)="viewUserProfile(user.id)"
title="Voir le profil"
>
<ng-icon name="lucideEye"></ng-icon>
</button>
<button
class="btn btn-outline-warning btn-sm"
(click)="resetPassword(user)"
title="Réinitialiser le mot de passe"
>
<ng-icon name="lucideKey"></ng-icon>
</button>
@if (user.enabled) {
<button
class="btn btn-outline-secondary btn-sm"
(click)="disableUser(user)"
title="Désactiver l'utilisateur"
>
<ng-icon name="lucideUserX"></ng-icon>
</button>
} @else {
<button
class="btn btn-outline-success btn-sm"
(click)="enableUser(user)"
title="Activer l'utilisateur"
>
<ng-icon name="lucideUserCheck"></ng-icon>
</button>
}
@if (showDeleteButton) {
<button
class="btn btn-outline-danger btn-sm"
(click)="deleteUser(user)"
title="Supprimer l'utilisateur"
>
<ng-icon name="lucideTrash2"></ng-icon>
</button>
}
</div>
</td>
</tr>
}
@empty {
<tr>
<td [attr.colspan]="getColumnCount()" class="text-center py-4">
<div class="text-muted">
<ng-icon name="lucideUsers" class="fs-1 mb-3 opacity-50"></ng-icon>
<h5 class="mb-2">Aucun utilisateur trouvé</h5>
<p class="mb-3">Aucun utilisateur ne correspond à vos critères de recherche.</p>
@if (showCreateButton) {
<button class="btn btn-primary" (click)="openCreateUserModal.emit()">
<ng-icon name="lucideUserPlus" class="me-1"></ng-icon>
Créer le premier utilisateur
</button>
}
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
<!-- Pagination -->
@if (totalPages > 1) {
<div class="d-flex justify-content-between align-items-center mt-3">
<div class="text-muted">
Affichage de {{ getStartIndex() }} à {{ getEndIndex() }} sur {{ totalItems }} utilisateurs
</div>
<nav>
<ngb-pagination
[collectionSize]="totalItems"
[page]="currentPage"
[pageSize]="itemsPerPage"
[maxSize]="5"
[rotate]="true"
[boundaryLinks]="true"
(pageChange)="onPageChange($event)"
/>
</nav>
</div>
}
<!-- Résumé des résultats -->
@if (displayedUsers.length > 0) {
<div class="mt-3 pt-3 border-top">
<div class="row text-center">
<div class="col">
<small class="text-muted">
<strong>Total :</strong> {{ allUsers.length }} utilisateurs
</small>
</div>
<div class="col">
<small class="text-muted">
<strong>Actifs :</strong> {{ getEnabledUsersCount() }}
</small>
</div>
<div class="col">
<small class="text-muted">
<strong>Admins :</strong> {{ getUsersCountByRole(UserRole.DCB_ADMIN) }}
</small>
</div>
<div class="col">
<small class="text-muted">
<strong>Support :</strong> {{ getUsersCountByRole(UserRole.DCB_SUPPORT) }}
</small>
</div>
</div>
</div>
}
}
</div>
</app-ui-card>