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(); // Configuration readonly UserRole = UserRole; readonly UserType = UserType; readonly UserUtils = UserUtils; // Inputs @Input() canCreateUsers: boolean = false; @Input() canDeleteUsers: boolean = false; // Outputs @Output() userSelected = new EventEmitter(); @Output() openCreateUserModal = new EventEmitter(); @Output() resetPasswordRequested = new EventEmitter(); @Output() deleteUserRequested = new EventEmitter(); // 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; } }