597 lines
17 KiB
TypeScript
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-old.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;
|
|
}
|
|
} |