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

597 lines
17 KiB
TypeScript

import { Component, inject, OnInit, Output, EventEmitter, ChangeDetectorRef, Input, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { NgIcon } from '@ng-icons/core';
import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable, Subject, map, of } from 'rxjs';
import { catchError, takeUntil } from 'rxjs/operators';
import {
PaginatedUserResponse,
User,
UserRole,
UserType,
UserUtils
} from '@core/models/dcb-bo-hub-user.model';
import { HubUsersService } from '../hub-users.service';
import { RoleManagementService } from '@core/services/hub-users-roles-management.service';
import { AuthService } from '@core/services/auth.service';
import { UiCard } from '@app/components/ui-card';
@Component({
selector: 'app-hub-users-list',
standalone: true,
imports: [
CommonModule,
FormsModule,
NgIcon,
UiCard,
NgbPaginationModule
],
templateUrl: './hub-users-list.html',
})
export class HubUsersList implements OnInit, OnDestroy {
private authService = inject(AuthService);
private hubUsersService = inject(HubUsersService);
protected roleService = inject(RoleManagementService);
private cdRef = inject(ChangeDetectorRef);
private destroy$ = new Subject<void>();
// Configuration
readonly UserRole = UserRole;
readonly UserType = UserType;
readonly UserUtils = UserUtils;
// Inputs
@Input() canCreateUsers: boolean = false;
@Input() canDeleteUsers: boolean = false;
// Outputs
@Output() userSelected = new EventEmitter<string>();
@Output() openCreateUserModal = new EventEmitter<void>();
@Output() resetPasswordRequested = new EventEmitter<string>();
@Output() deleteUserRequested = new EventEmitter<string>();
// Données
allUsers: User[] = [];
filteredUsers: User[] = [];
displayedUsers: User[] = [];
// États
loading = false;
error = '';
// Recherche et filtres
searchTerm = '';
statusFilter: 'all' | 'enabled' | 'disabled' = 'all';
emailVerifiedFilter: 'all' | 'verified' | 'not-verified' = 'all';
roleFilter: UserRole | 'all' = 'all';
contextFilter: 'all' | 'hub' | 'merchant' = 'all';
// Pagination
currentPage = 1;
itemsPerPage = 10;
totalItems = 0;
totalPages = 0;
// Tri
sortField: keyof User = 'username';
sortDirection: 'asc' | 'desc' = 'asc';
// Rôles disponibles pour le filtre
availableRoles: { value: UserRole | 'all'; label: string, description: string }[] = [];
// Permissions
currentUserRole: UserRole | null = null;
canViewAllUsers = false;
// Statistiques
statistics: any = null;
// Getters pour la logique conditionnelle
get showCreateButton(): boolean {
return this.canCreateUsers;
}
get showDeleteButton(): boolean {
return this.canDeleteUsers;
}
ngOnInit() {
this.loadCurrentUserPermissions();
this.initializeAvailableRoles();
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
private loadCurrentUserPermissions() {
this.authService.getUserProfile()
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (user) => {
this.currentUserRole = this.extractUserRole(user);
this.canViewAllUsers = this.canViewAllUsersCheck(this.currentUserRole);
console.log('Hub User Context Loaded:', {
role: this.currentUserRole,
canViewAllUsers: this.canViewAllUsers
});
this.loadUsers();
},
error: (error) => {
console.error('Error loading current user permissions:', error);
this.fallbackPermissions();
this.loadUsers();
}
});
}
private extractUserRole(user: any): UserRole | null {
const userRoles = this.authService.getCurrentUserRoles();
if (userRoles && userRoles.length > 0) {
return userRoles[0];
}
return null;
}
private canViewAllUsersCheck(role: UserRole | null): boolean {
if (!role) return false;
const canViewAllRoles = [
UserRole.DCB_ADMIN,
UserRole.DCB_SUPPORT
];
return canViewAllRoles.includes(role);
}
private fallbackPermissions(): void {
this.currentUserRole = this.authService.getCurrentUserRole();
this.canViewAllUsers = this.canViewAllUsersCheck(this.currentUserRole);
}
private initializeAvailableRoles() {
this.availableRoles = [
{ value: 'all', label: 'Tous les rôles', description: 'Tous les Roles' },
{ value: UserRole.DCB_ADMIN, label: 'DCB Admin', description: 'Administrateur système' },
{ value: UserRole.DCB_SUPPORT, label: 'DCB Support', description: 'Support technique' },
//{ value: UserRole.DCB_PARTNER, label: 'DCB Partner', description: 'Partenaire commercial' },
];
}
loadUsers() {
this.loading = true;
this.error = '';
if (this.canViewAllUsers) {
// Vue admin : tous les utilisateurs (Hub + Merchant)
this.loadAllUsers();
} else {
// Vue normale : utilisateurs Hub seulement
this.loadHubUsers();
}
}
private loadAllUsers() {
this.hubUsersService.getAllUsers()
.pipe(
takeUntil(this.destroy$),
catchError(error => {
console.error('Error loading all users:', error);
this.error = 'Erreur lors du chargement de tous les utilisateurs';
return of(null);
})
)
.subscribe({
next: (overview) => {
if (overview) {
// Combiner Hub + Merchant users
this.allUsers = [...overview.hubUsers, ...overview.merchantUsers];
this.statistics = overview.statistics;
console.log(`✅ Admin view: ${overview.hubUsers.length} hub + ${overview.merchantUsers.length} merchant users`);
this.applyFiltersAndPagination();
}
this.loading = false;
this.cdRef.detectChanges();
},
error: () => {
this.loading = false;
this.allUsers = [];
this.filteredUsers = [];
this.displayedUsers = [];
this.cdRef.detectChanges();
}
});
}
private loadHubUsers() {
this.hubUsersService.getHubUsers()
.pipe(
map((response: PaginatedUserResponse) => response.users),
takeUntil(this.destroy$),
catchError(error => {
console.error('Error loading hub users:', error);
this.error = 'Erreur lors du chargement des utilisateurs Hub';
return of([] as User[]);
})
)
.subscribe({
next: (users) => {
this.allUsers = users || [];
console.log(`✅ Loaded ${this.allUsers.length} hub users`);
this.applyFiltersAndPagination();
this.loading = false;
this.cdRef.detectChanges();
},
error: () => {
this.error = 'Erreur lors du chargement des utilisateurs Hub';
this.loading = false;
this.allUsers = [];
this.filteredUsers = [];
this.displayedUsers = [];
this.cdRef.detectChanges();
}
});
}
get isAdminView(): boolean {
return this.canViewAllUsers;
}
get showStatistics(): boolean {
return this.isAdminView && this.statistics !== null;
}
get viewDescription(): string {
if (this.isAdminView) {
return 'Vue administrative - Tous les utilisateurs (Hub + Merchant)';
} else {
return 'Utilisateurs Hub DCB';
}
}
// Recherche et filtres
onSearch() {
this.currentPage = 1;
this.applyFiltersAndPagination();
}
onClearFilters() {
this.searchTerm = '';
this.statusFilter = 'all';
this.emailVerifiedFilter = 'all';
this.roleFilter = 'all';
this.contextFilter = 'all';
this.currentPage = 1;
this.applyFiltersAndPagination();
}
applyFiltersAndPagination() {
if (!this.allUsers) {
this.allUsers = [];
}
// Appliquer les filtres
this.filteredUsers = this.allUsers.filter(user => {
const matchesSearch = !this.searchTerm ||
user.username.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
user.email.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
(user.firstName && user.firstName.toLowerCase().includes(this.searchTerm.toLowerCase())) ||
(user.lastName && user.lastName.toLowerCase().includes(this.searchTerm.toLowerCase()));
const matchesStatus = this.statusFilter === 'all' ||
(this.statusFilter === 'enabled' && user.enabled) ||
(this.statusFilter === 'disabled' && !user.enabled);
const matchesEmailVerified = this.emailVerifiedFilter === 'all' ||
(this.emailVerifiedFilter === 'verified' && user.emailVerified) ||
(this.emailVerifiedFilter === 'not-verified' && !user.emailVerified);
const matchesRole = this.roleFilter === 'all' ||
(user.role && user.role.includes(this.roleFilter));
// Filtre par contexte (seulement pour la vue admin)
const matchesContext = !this.isAdminView ||
(this.contextFilter === 'all' ||
(this.contextFilter === 'hub' && user.userType === UserType.HUB) ||
(this.contextFilter === 'merchant' && user.userType === UserType.MERCHANT_PARTNER));
return matchesSearch && matchesStatus && matchesEmailVerified && matchesRole && matchesContext;
});
// Appliquer le tri
this.filteredUsers.sort((a, b) => {
const aValue = a[this.sortField];
const bValue = b[this.sortField];
if (aValue === bValue) return 0;
let comparison = 0;
if (typeof aValue === 'string' && typeof bValue === 'string') {
comparison = aValue.localeCompare(bValue);
} else if (typeof aValue === 'number' && typeof bValue === 'number') {
comparison = aValue - bValue;
} else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {
comparison = (aValue === bValue) ? 0 : aValue ? -1 : 1;
}
return this.sortDirection === 'asc' ? comparison : -comparison;
});
// Calculer la pagination
this.totalItems = this.filteredUsers.length;
this.totalPages = Math.ceil(this.totalItems / this.itemsPerPage);
// Appliquer la pagination
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
const endIndex = startIndex + this.itemsPerPage;
this.displayedUsers = this.filteredUsers.slice(startIndex, endIndex);
}
// Tri
sort(field: keyof User) {
if (this.sortField === field) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
this.sortField = field;
this.sortDirection = 'asc';
}
this.applyFiltersAndPagination();
}
getSortIcon(field: string): string {
if (this.sortField !== field) return 'lucideArrowUpDown';
return this.sortDirection === 'asc' ? 'lucideArrowUp' : 'lucideArrowDown';
}
// Pagination
onPageChange(page: number) {
this.currentPage = page;
this.applyFiltersAndPagination();
}
getStartIndex(): number {
return (this.currentPage - 1) * this.itemsPerPage + 1;
}
getEndIndex(): number {
return Math.min(this.currentPage * this.itemsPerPage, this.totalItems);
}
// Actions
viewUserProfile(userId: string) {
this.userSelected.emit(userId);
}
resetPassword(user: User) {
this.resetPasswordRequested.emit(user.id);
}
deleteUser(user: User) {
this.deleteUserRequested.emit(user.id);
}
enableUser(user: User) {
this.hubUsersService.enableHubUser(user.id)
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (updatedUser) => {
const index = this.allUsers.findIndex(u => u.id === user.id);
if (index !== -1) {
this.allUsers[index] = updatedUser;
}
this.applyFiltersAndPagination();
this.cdRef.detectChanges();
},
error: (error) => {
console.error('Error enabling hub user:', error);
this.error = 'Erreur lors de l\'activation de l\'utilisateur';
this.cdRef.detectChanges();
}
});
}
disableUser(user: User) {
this.hubUsersService.disableHubUser(user.id)
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (updatedUser) => {
const index = this.allUsers.findIndex(u => u.id === user.id);
if (index !== -1) {
this.allUsers[index] = updatedUser;
}
this.applyFiltersAndPagination();
this.cdRef.detectChanges();
},
error: (error) => {
console.error('Error disabling hub user:', error);
this.error = 'Erreur lors de la désactivation de l\'utilisateur';
this.cdRef.detectChanges();
}
});
}
// Utilitaires d'affichage
getStatusBadgeClass(user: User): string {
if (!user.enabled) return 'badge bg-danger';
if (!user.emailVerified) return 'badge bg-warning';
return 'badge bg-success';
}
getStatusText(user: User): string {
if (!user.enabled) return 'Désactivé';
if (!user.emailVerified) return 'Email non vérifié';
return 'Actif';
}
getRoleBadgeClass(role: string | UserRole): string {
return this.roleService.getRoleBadgeClass(role);
}
getRoleLabel(role: string | UserRole): string {
return this.roleService.getRoleLabel(role);
}
getRoleIcon(role: string | UserRole): string {
return this.roleService.getRoleIcon(role);
}
getRoleDescription(role: string | UserRole): string {
const roleInfo = this.availableRoles.find(r => r.value === role);
return roleInfo?.description || 'Description non disponible';
}
formatTimestamp(timestamp: number | undefined): string {
if (!timestamp) return 'Non disponible';
return new Date(timestamp).toLocaleDateString('fr-FR', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
getUserInitials(user: User): string {
return (user.firstName?.charAt(0) || '') + (user.lastName?.charAt(0) || '') || 'U';
}
getUserDisplayName(user: User): string {
if (user.firstName && user.lastName) {
return `${user.firstName} ${user.lastName}`;
}
return user.username;
}
getEnabledUsersCount(): number {
return this.allUsers.filter(user => user.enabled).length;
}
getDisabledUsersCount(): number {
return this.allUsers.filter(user => !user.enabled).length;
}
userHasRole(user: User, role: UserRole): boolean {
return UserUtils.hasRole(user, role);
}
// Recherche rapide par rôle
filterByRole(role: UserRole | 'all') {
this.roleFilter = role;
this.currentPage = 1;
this.applyFiltersAndPagination();
}
// Recharger les données
refreshData() {
this.loadUsers();
}
// Méthodes pour le template
getCardTitle(): string {
return 'Liste des Utilisateurs Hub';
}
getHelperText(): string {
return 'Gérez les accès utilisateurs de votre plateforme DCB';
}
getHelperIcon(): string {
return 'lucideUsers';
}
getContextAlertClass(): string {
return this.isAdminView ? 'alert-warning' : 'alert-secondary';
}
getContextIcon(): string {
return this.isAdminView ? 'lucideShield' : 'lucideUsers';
}
getContextTitle(): string {
return this.isAdminView ? 'Vue Administrative Globale :' : 'Utilisateurs Hub DCB :';
}
getContextDescription(): string {
return this.isAdminView
? 'Vous visualisez tous les utilisateurs Hub et Merchant de la plateforme'
: 'Gérez les accès utilisateurs de votre plateforme DCB';
}
showContextAlert(): boolean {
return true;
}
// Méthode pour compter les utilisateurs par rôle
getUsersCountByRole(role: UserRole): number {
if (!this.allUsers || this.allUsers.length === 0) return 0;
return this.allUsers.filter(user =>
user.role && user.role.includes(role)
).length;
}
getLoadingText(): string {
return 'Chargement des utilisateurs...';
}
getEmptyStateTitle(): string {
return 'Aucun utilisateur trouvé';
}
getEmptyStateDescription(): string {
return 'Aucun utilisateur ne correspond à vos critères de recherche.';
}
getEmptyStateButtonText(): string {
return 'Créer le premier utilisateur';
}
getColumnCount(): number {
return this.isAdminView ? 7 : 6;
}
showUserTypeColumn(): boolean {
return this.isAdminView;
}
showMerchantPartnerColumn(): boolean {
return this.isAdminView;
}
// Statistiques
getTotalUsersCount(): number {
return this.allUsers.length;
}
getActiveUsersCount(): number {
return this.allUsers.filter(user => user.enabled).length;
}
getVerifiedUsersCount(): number {
return this.allUsers.filter(user => user.emailVerified).length;
}
// Méthodes spécifiques pour la vue admin
getHubUsersCount(): number {
if (!this.isAdminView || !this.statistics) return 0;
return this.statistics.totalHubUsers || 0;
}
getMerchantUsersCount(): number {
if (!this.isAdminView || !this.statistics) return 0;
return this.statistics.totalMerchantUsers || 0;
}
getTotalUsersCountAdmin(): number {
if (!this.isAdminView || !this.statistics) return 0;
return this.statistics.totalUsers || 0;
}
}