695 lines
22 KiB
TypeScript
695 lines
22 KiB
TypeScript
// src/app/modules/merchant-users/list/list.ts
|
||
import { Component, inject, OnInit, Output, EventEmitter, ChangeDetectorRef, OnDestroy } from '@angular/core';
|
||
import { CommonModule } from '@angular/common';
|
||
import { FormsModule } from '@angular/forms';
|
||
import { NgIcon } from '@ng-icons/core';
|
||
import { NgbPaginationModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
|
||
import { catchError, map, of, Subject, takeUntil } from 'rxjs';
|
||
|
||
import {
|
||
MerchantUserDto,
|
||
PaginatedUserResponse,
|
||
SearchUsersParams,
|
||
UserRole,
|
||
UserType
|
||
} from '@core/models/dcb-bo-hub-user.model';
|
||
|
||
import { MerchantUsersService } from '../services/merchant-users.service';
|
||
import { HubUsersService } from '../../hub-users/services/hub-users.service';
|
||
import { AuthService } from '@core/services/auth.service';
|
||
import { UiCard } from '@app/components/ui-card';
|
||
|
||
@Component({
|
||
selector: 'app-merchant-users-list',
|
||
standalone: true,
|
||
imports: [
|
||
CommonModule,
|
||
FormsModule,
|
||
NgIcon,
|
||
UiCard,
|
||
NgbPaginationModule,
|
||
NgbDropdownModule
|
||
],
|
||
templateUrl: './list.html',
|
||
})
|
||
export class MerchantUsersList implements OnInit, OnDestroy {
|
||
private merchantUsersService = inject(MerchantUsersService);
|
||
private hubUsersService = inject(HubUsersService);
|
||
private authService = inject(AuthService);
|
||
private cdRef = inject(ChangeDetectorRef);
|
||
private destroy$ = new Subject<void>();
|
||
|
||
readonly UserRole = UserRole;
|
||
readonly UserType = UserType;
|
||
|
||
@Output() userSelected = new EventEmitter<string>();
|
||
@Output() openCreateModal = new EventEmitter<void>();
|
||
@Output() openResetPasswordModal = new EventEmitter<string>();
|
||
@Output() openDeleteUserModal = new EventEmitter<string>();
|
||
|
||
// Données
|
||
allUsers: MerchantUserDto[] = [];
|
||
filteredUsers: MerchantUserDto[] = [];
|
||
displayedUsers: MerchantUserDto[] = [];
|
||
|
||
// États
|
||
loading = false;
|
||
error = '';
|
||
|
||
// Recherche et filtres
|
||
searchTerm = '';
|
||
statusFilter: 'all' | 'enabled' | 'disabled' = 'all';
|
||
emailVerifiedFilter: 'all' | 'verified' | 'not-verified' = 'all';
|
||
roleFilter: UserRole | 'all' = 'all';
|
||
|
||
// Pagination
|
||
currentPage = 1;
|
||
itemsPerPage = 10;
|
||
totalItems = 0;
|
||
totalPages = 0;
|
||
|
||
// Tri
|
||
sortField: keyof MerchantUserDto = 'username';
|
||
sortDirection: 'asc' | 'desc' = 'asc';
|
||
|
||
// Rôles disponibles pour le filtre
|
||
availableRoles: { value: UserRole | 'all'; label: string }[] = [
|
||
{ value: 'all', label: 'Tous les rôles' },
|
||
{ value: UserRole.DCB_PARTNER_ADMIN, label: 'Administrateurs' },
|
||
{ value: UserRole.DCB_PARTNER_MANAGER, label: 'Managers' },
|
||
{ value: UserRole.DCB_PARTNER_SUPPORT, label: 'Support' }
|
||
];
|
||
|
||
// ID du merchant partner courant et permissions
|
||
currentMerchantPartnerId: string = '';
|
||
currentUserRole: UserRole | null = null;
|
||
isHubAdminOrSupport = false;
|
||
canViewAllMerchants = false;
|
||
isDcbPartner = false;
|
||
|
||
ngOnInit() {
|
||
this.loadCurrentUserPermissions();
|
||
}
|
||
|
||
ngOnDestroy(): void {
|
||
this.destroy$.next();
|
||
this.destroy$.complete();
|
||
}
|
||
|
||
private loadCurrentUserPermissions() {
|
||
this.authService.getProfile().subscribe({
|
||
next: (user: any) => {
|
||
// Méthode robuste pour récupérer le rôle
|
||
this.currentUserRole = this.extractUserRole(user);
|
||
|
||
// Déterminer le type d'utilisateur avec des méthodes plus robustes
|
||
this.isHubAdminOrSupport = this.isHubAdminOrSupportRole(this.currentUserRole);
|
||
this.isDcbPartner = this.isDcbPartnerRole(this.currentUserRole);
|
||
this.canViewAllMerchants = this.canViewAllMerchantsCheck(this.currentUserRole);
|
||
|
||
|
||
// Déterminer le merchantPartnerId
|
||
if(this.isDcbPartner){
|
||
this.currentMerchantPartnerId = user.id;
|
||
}
|
||
else if(!this.isDcbPartner || !this.isHubAdminOrSupport) {
|
||
this.currentMerchantPartnerId = this.extractMerchantPartnerId(user);
|
||
}
|
||
|
||
this.loadUsers();
|
||
},
|
||
error: (error) => {
|
||
console.error('❌ Error loading current user permissions:', error);
|
||
// Fallback: utiliser les méthodes d'AuthService
|
||
this.fallbackPermissions();
|
||
this.loadUsers(); // Charger quand même les utilisateurs
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Méthode robuste pour extraire le rôle de l'utilisateur
|
||
*/
|
||
private extractUserRole(user: any): UserRole | null {
|
||
console.log('🔍 Extracting user role from:', user);
|
||
|
||
// 1. Essayer depuis les rôles du token (méthode principale)
|
||
const tokenRoles = this.authService.getCurrentUserRoles();
|
||
if (tokenRoles && tokenRoles.length > 0) {
|
||
console.log('✅ Role from token:', tokenRoles[0]);
|
||
return tokenRoles[0];
|
||
}
|
||
|
||
// 2. Essayer depuis le profil user.role
|
||
if (user?.role && Object.values(UserRole).includes(user.role)) {
|
||
console.log('✅ Role from user.role:', user.role);
|
||
return user.role as UserRole;
|
||
}
|
||
|
||
// 3. Essayer depuis user.userType pour déduire le rôle
|
||
if (user?.userType) {
|
||
const roleFromType = this.getRoleFromUserType(user.userType);
|
||
if (roleFromType) {
|
||
console.log('✅ Role deduced from userType:', roleFromType);
|
||
return roleFromType;
|
||
}
|
||
}
|
||
|
||
// 4. Essayer depuis les attributs étendus
|
||
if (user?.attributes?.role?.[0]) {
|
||
const roleFromAttributes = user.attributes.role[0];
|
||
if (Object.values(UserRole).includes(roleFromAttributes as UserRole)) {
|
||
console.log('✅ Role from attributes:', roleFromAttributes);
|
||
return roleFromAttributes as UserRole;
|
||
}
|
||
}
|
||
|
||
console.warn('❌ No valid role found in user profile');
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Déduire le rôle à partir du userType
|
||
*/
|
||
private getRoleFromUserType(userType: string): UserRole | null {
|
||
const typeMapping: { [key: string]: UserRole } = {
|
||
[UserType.HUB]: UserRole.DCB_ADMIN, // Fallback pour HUB
|
||
[UserType.MERCHANT]: UserRole.DCB_PARTNER_ADMIN, // Fallback pour MERCHANT
|
||
};
|
||
|
||
return typeMapping[userType] || null;
|
||
}
|
||
|
||
/**
|
||
* Vérifier si l'utilisateur est Hub Admin ou Support
|
||
*/
|
||
private isHubAdminOrSupportRole(role: UserRole | null): boolean {
|
||
if (!role) return false;
|
||
|
||
const hubAdminSupportRoles = [
|
||
UserRole.DCB_ADMIN,
|
||
UserRole.DCB_SUPPORT,
|
||
UserRole.DCB_PARTNER // DCB_PARTNER peut aussi être considéré comme Hub
|
||
];
|
||
|
||
return hubAdminSupportRoles.includes(role);
|
||
}
|
||
|
||
/**
|
||
* Vérifier si l'utilisateur est DCB Partner
|
||
*/
|
||
private isDcbPartnerRole(role: UserRole | null): boolean {
|
||
if (!role) return false;
|
||
|
||
const partnerRoles = [
|
||
UserRole.DCB_PARTNER,
|
||
UserRole.DCB_PARTNER_ADMIN,
|
||
UserRole.DCB_PARTNER_MANAGER,
|
||
UserRole.DCB_PARTNER_SUPPORT
|
||
];
|
||
|
||
return partnerRoles.includes(role);
|
||
}
|
||
|
||
/**
|
||
* Vérifier si l'utilisateur peut voir tous les merchants
|
||
*/
|
||
private canViewAllMerchantsCheck(role: UserRole | null): boolean {
|
||
if (!role) return false;
|
||
|
||
const canViewAllRoles = [
|
||
UserRole.DCB_ADMIN,
|
||
UserRole.DCB_SUPPORT
|
||
];
|
||
|
||
return canViewAllRoles.includes(role);
|
||
}
|
||
|
||
/**
|
||
* Extraire le merchantPartnerId de manière robuste
|
||
*/
|
||
private extractMerchantPartnerId(user: any): string {
|
||
console.log('🔍 Extracting merchantPartnerId from:', user);
|
||
|
||
// 1. Essayer depuis merchantPartnerId direct
|
||
if (user?.merchantPartnerId) {
|
||
console.log('✅ merchantPartnerId from direct property:', user.merchantPartnerId);
|
||
return user.merchantPartnerId;
|
||
}
|
||
|
||
// 2. Essayer depuis les attributs
|
||
if (user?.attributes?.merchantPartnerId?.[0]) {
|
||
console.log('✅ merchantPartnerId from attributes:', user.attributes.merchantPartnerId[0]);
|
||
return user.attributes.merchantPartnerId[0];
|
||
}
|
||
|
||
// 3. Essayer depuis AuthService
|
||
const authServiceMerchantId = this.authService.getCurrentMerchantPartnerId();
|
||
if (authServiceMerchantId) {
|
||
console.log('✅ merchantPartnerId from AuthService:', authServiceMerchantId);
|
||
return authServiceMerchantId;
|
||
}
|
||
|
||
// 4. Pour les rôles Hub, pas de merchantPartnerId
|
||
if (this.isHubAdminOrSupport) {
|
||
console.log('ℹ️ Hub user - no merchantPartnerId');
|
||
return '';
|
||
}
|
||
|
||
console.warn('❌ No merchantPartnerId found');
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Fallback en cas d'erreur de chargement du profil
|
||
*/
|
||
private fallbackPermissions(): void {
|
||
console.warn('🔄 Using fallback permissions');
|
||
|
||
// Utiliser les méthodes d'AuthService comme fallback
|
||
this.currentUserRole = this.authService.getCurrentUserRole();
|
||
this.isHubAdminOrSupport = this.authService.isHubUser() ||
|
||
this.authService.hasRole(UserRole.DCB_ADMIN) ||
|
||
this.authService.hasRole(UserRole.DCB_SUPPORT);
|
||
this.isDcbPartner = this.authService.isMerchantUser() ||
|
||
this.authService.hasRole(UserRole.DCB_PARTNER);
|
||
this.canViewAllMerchants = this.authService.canViewAllMerchants();
|
||
this.currentMerchantPartnerId = this.authService.getCurrentMerchantPartnerId() || '';
|
||
|
||
console.log('🔄 Fallback permissions:', {
|
||
currentUserRole: this.currentUserRole,
|
||
isHubAdminOrSupport: this.isHubAdminOrSupport,
|
||
isDcbPartner: this.isDcbPartner,
|
||
canViewAllMerchants: this.canViewAllMerchants,
|
||
currentMerchantPartnerId: this.currentMerchantPartnerId
|
||
});
|
||
}
|
||
|
||
loadUsers() {
|
||
this.loading = true;
|
||
this.error = '';
|
||
|
||
let usersObservable;
|
||
|
||
if (this.canViewAllMerchants && !this.currentMerchantPartnerId) {
|
||
console.log('🔍 Loading ALL merchant users (Hub Admin/Support)');
|
||
usersObservable = this.hubUsersService.findAllMerchantUsers(this.currentPage, this.itemsPerPage).pipe(
|
||
map((response: PaginatedUserResponse) => {
|
||
console.log('✅ All merchant users loaded:', response.users.length);
|
||
return response.users as MerchantUserDto[];
|
||
}),
|
||
catchError(error => {
|
||
console.error('❌ Error loading all merchant users:', error);
|
||
this.error = 'Erreur lors du chargement de tous les utilisateurs marchands';
|
||
return of([]);
|
||
})
|
||
);
|
||
} else if (this.currentMerchantPartnerId) {
|
||
console.log(`🔍 Loading merchant users for partner: ${this.currentMerchantPartnerId}`);
|
||
usersObservable = this.merchantUsersService.getMerchantUsersByPartner(this.currentMerchantPartnerId).pipe(
|
||
catchError(error => {
|
||
console.error('❌ Error loading merchant users by partner:', error);
|
||
this.error = 'Erreur lors du chargement des utilisateurs du partenaire';
|
||
return of([]);
|
||
})
|
||
);
|
||
} else {
|
||
console.log('🔍 Loading my merchant users');
|
||
usersObservable = this.merchantUsersService.getMyMerchantUsers(this.currentMerchantPartnerId).pipe(
|
||
catchError(error => {
|
||
console.error('❌ Error loading my merchant users:', error);
|
||
this.error = 'Erreur lors du chargement de mes utilisateurs marchands';
|
||
return of([]);
|
||
})
|
||
);
|
||
}
|
||
|
||
usersObservable
|
||
.pipe(takeUntil(this.destroy$))
|
||
.subscribe({
|
||
next: (users: MerchantUserDto[]) => {
|
||
this.allUsers = users || [];
|
||
console.log(`✅ Loaded ${this.allUsers.length} merchant users`);
|
||
|
||
this.applyFiltersAndPagination();
|
||
this.loading = false;
|
||
this.cdRef.detectChanges();
|
||
},
|
||
error: (error: any) => {
|
||
this.error = 'Erreur lors du chargement des utilisateurs marchands';
|
||
this.loading = false;
|
||
|
||
this.allUsers = [];
|
||
this.filteredUsers = [];
|
||
this.displayedUsers = [];
|
||
this.cdRef.detectChanges();
|
||
console.error('❌ Error in users subscription:', error);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Recherche et filtres
|
||
onSearch() {
|
||
this.currentPage = 1;
|
||
this.applyFiltersAndPagination();
|
||
}
|
||
|
||
onClearFilters() {
|
||
this.searchTerm = '';
|
||
this.statusFilter = 'all';
|
||
this.emailVerifiedFilter = 'all';
|
||
this.roleFilter = 'all';
|
||
this.currentPage = 1;
|
||
this.applyFiltersAndPagination();
|
||
}
|
||
|
||
applyFiltersAndPagination() {
|
||
// Vérifier que allUsers est défini
|
||
if (!this.allUsers) {
|
||
this.allUsers = [];
|
||
}
|
||
|
||
console.log(`🔍 Applying filters to ${this.allUsers.length} users`);
|
||
|
||
// Appliquer les filtres
|
||
this.filteredUsers = this.allUsers.filter(user => {
|
||
// Filtre de recherche
|
||
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()));
|
||
|
||
// Filtre par statut
|
||
const matchesStatus = this.statusFilter === 'all' ||
|
||
(this.statusFilter === 'enabled' && user.enabled) ||
|
||
(this.statusFilter === 'disabled' && !user.enabled);
|
||
|
||
// Filtre par email vérifié
|
||
const matchesEmailVerified = this.emailVerifiedFilter === 'all' ||
|
||
(this.emailVerifiedFilter === 'verified' && user.emailVerified) ||
|
||
(this.emailVerifiedFilter === 'not-verified' && !user.emailVerified);
|
||
|
||
// Filtre par rôle
|
||
const matchesRole = this.roleFilter === 'all' || user.role === this.roleFilter;
|
||
|
||
return matchesSearch && matchesStatus && matchesEmailVerified && matchesRole;
|
||
});
|
||
|
||
console.log(`✅ Filtered to ${this.filteredUsers.length} users`);
|
||
|
||
// 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);
|
||
|
||
console.log(`📄 Pagination: page ${this.currentPage} of ${this.totalPages}, showing ${this.displayedUsers.length} users`);
|
||
}
|
||
|
||
// Tri
|
||
sort(field: keyof MerchantUserDto) {
|
||
if (this.sortField === field) {
|
||
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
||
} else {
|
||
this.sortField = field;
|
||
this.sortDirection = 'asc';
|
||
}
|
||
console.log(`🔀 Sorting by ${field} (${this.sortDirection})`);
|
||
this.applyFiltersAndPagination();
|
||
}
|
||
|
||
getSortIcon(field: keyof MerchantUserDto): string {
|
||
if (this.sortField !== field) return 'lucideArrowUpDown';
|
||
return this.sortDirection === 'asc' ? 'lucideArrowUp' : 'lucideArrowDown';
|
||
}
|
||
|
||
// Pagination
|
||
onPageChange(page: number) {
|
||
console.log(`📄 Changing to page ${page}`);
|
||
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) {
|
||
console.log(`👤 Viewing user profile: ${userId}`);
|
||
this.userSelected.emit(userId);
|
||
}
|
||
|
||
// Méthode pour réinitialiser le mot de passe
|
||
resetPassword(user: MerchantUserDto) {
|
||
console.log(`🔑 Resetting password for user: ${user.username}`);
|
||
this.openResetPasswordModal.emit(user.id);
|
||
}
|
||
|
||
// Méthode pour ouvrir le modal de suppression
|
||
deleteUser(user: MerchantUserDto) {
|
||
console.log(`🗑️ Deleting user: ${user.username}`);
|
||
this.openDeleteUserModal.emit(user.id);
|
||
}
|
||
|
||
// Activer un utilisateur
|
||
enableUser(user: MerchantUserDto) {
|
||
console.log(`✅ Enabling user: ${user.username}`);
|
||
this.merchantUsersService.enableMerchantUser(user.id)
|
||
.pipe(takeUntil(this.destroy$))
|
||
.subscribe({
|
||
next: (updatedUser) => {
|
||
console.log(`✅ User ${user.username} enabled successfully`);
|
||
// Mettre à jour l'utilisateur dans la liste
|
||
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 merchant user:', error);
|
||
this.error = 'Erreur lors de l\'activation de l\'utilisateur';
|
||
this.cdRef.detectChanges();
|
||
}
|
||
});
|
||
}
|
||
|
||
// Désactiver un utilisateur
|
||
disableUser(user: MerchantUserDto) {
|
||
console.log(`❌ Disabling user: ${user.username}`);
|
||
this.merchantUsersService.disableMerchantUser(user.id)
|
||
.pipe(takeUntil(this.destroy$))
|
||
.subscribe({
|
||
next: (updatedUser) => {
|
||
console.log(`✅ User ${user.username} disabled successfully`);
|
||
// Mettre à jour l'utilisateur dans la liste
|
||
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 merchant user:', error);
|
||
this.error = 'Erreur lors de la désactivation de l\'utilisateur';
|
||
this.cdRef.detectChanges();
|
||
}
|
||
});
|
||
}
|
||
|
||
// ==================== UTILITAIRES D'AFFICHAGE ====================
|
||
|
||
getStatusBadgeClass(user: MerchantUserDto): string {
|
||
if (!user.enabled) return 'badge bg-danger';
|
||
if (!user.emailVerified) return 'badge bg-warning';
|
||
return 'badge bg-success';
|
||
}
|
||
|
||
getStatusText(user: MerchantUserDto): string {
|
||
if (!user.enabled) return 'Désactivé';
|
||
if (!user.emailVerified) return 'Email non vérifié';
|
||
return 'Actif';
|
||
}
|
||
|
||
getRoleBadgeClass(role: UserRole): string {
|
||
switch (role) {
|
||
case UserRole.DCB_PARTNER_ADMIN:
|
||
return 'bg-danger';
|
||
case UserRole.DCB_PARTNER_MANAGER:
|
||
return 'bg-warning text-dark';
|
||
case UserRole.DCB_PARTNER_SUPPORT:
|
||
return 'bg-info text-white';
|
||
default:
|
||
return 'bg-secondary';
|
||
}
|
||
}
|
||
|
||
getRoleDisplayName(role: UserRole): string {
|
||
const roleNames = {
|
||
[UserRole.DCB_ADMIN]: 'Administrateur',
|
||
[UserRole.DCB_PARTNER]: 'Manager',
|
||
[UserRole.DCB_SUPPORT]: 'Support',
|
||
[UserRole.DCB_PARTNER_ADMIN]: 'Admin Marchand',
|
||
[UserRole.DCB_PARTNER_MANAGER]: 'Manager Marchand',
|
||
[UserRole.DCB_PARTNER_SUPPORT]: 'Support Marchand'
|
||
};
|
||
return roleNames[role] || role;
|
||
}
|
||
|
||
getRoleIcon(role: UserRole): string {
|
||
switch (role) {
|
||
case UserRole.DCB_PARTNER_ADMIN:
|
||
return 'lucideShield';
|
||
case UserRole.DCB_PARTNER_MANAGER:
|
||
return 'lucideUserCog';
|
||
case UserRole.DCB_PARTNER_SUPPORT:
|
||
return 'lucideHeadphones';
|
||
default:
|
||
return 'lucideUser';
|
||
}
|
||
}
|
||
|
||
formatTimestamp(timestamp: number): 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: MerchantUserDto): string {
|
||
return (user.firstName?.charAt(0) || '') + (user.lastName?.charAt(0) || '') || 'U';
|
||
}
|
||
|
||
getUserDisplayName(user: MerchantUserDto): string {
|
||
if (user.firstName && user.lastName) {
|
||
return `${user.firstName} ${user.lastName}`;
|
||
}
|
||
return user.username;
|
||
}
|
||
|
||
// ==================== STATISTIQUES ====================
|
||
|
||
getUsersCountByRole(role: UserRole): number {
|
||
return this.allUsers.filter(user => user.role === role).length;
|
||
}
|
||
|
||
getEnabledUsersCount(): number {
|
||
return this.allUsers.filter(user => user.enabled).length;
|
||
}
|
||
|
||
getDisabledUsersCount(): number {
|
||
return this.allUsers.filter(user => !user.enabled).length;
|
||
}
|
||
|
||
getEmailVerifiedCount(): number {
|
||
return this.allUsers.filter(user => user.emailVerified).length;
|
||
}
|
||
|
||
getTotalUsersCount(): number {
|
||
return this.allUsers.length;
|
||
}
|
||
|
||
// ==================== MÉTHODES UTILITAIRES ====================
|
||
|
||
hasRole(user: MerchantUserDto, role: UserRole): boolean {
|
||
return user.role === role;
|
||
}
|
||
|
||
isAdmin(user: MerchantUserDto): boolean {
|
||
return this.hasRole(user, UserRole.DCB_PARTNER_ADMIN);
|
||
}
|
||
|
||
isManager(user: MerchantUserDto): boolean {
|
||
return this.hasRole(user, UserRole.DCB_PARTNER_MANAGER);
|
||
}
|
||
|
||
isSupport(user: MerchantUserDto): boolean {
|
||
return this.hasRole(user, UserRole.DCB_PARTNER_SUPPORT);
|
||
}
|
||
|
||
// Recherche rapide par rôle
|
||
filterByRole(role: UserRole | 'all') {
|
||
this.roleFilter = role;
|
||
this.currentPage = 1;
|
||
this.applyFiltersAndPagination();
|
||
}
|
||
|
||
// Recherche via le service (pour des recherches plus complexes)
|
||
searchUsers() {
|
||
if (this.searchTerm.trim()) {
|
||
this.loading = true;
|
||
const searchParams: SearchUsersParams = {
|
||
query: this.searchTerm,
|
||
userType: UserType.MERCHANT
|
||
};
|
||
|
||
if (this.roleFilter !== 'all') {
|
||
searchParams.role = this.roleFilter as UserRole;
|
||
}
|
||
if (this.statusFilter !== 'all') {
|
||
searchParams.enabled = this.statusFilter === 'enabled';
|
||
}
|
||
|
||
console.log('🔍 Performing advanced search:', searchParams);
|
||
|
||
this.merchantUsersService.searchMerchantUsers(searchParams)
|
||
.pipe(takeUntil(this.destroy$))
|
||
.subscribe({
|
||
next: (users) => {
|
||
this.allUsers = users;
|
||
console.log(`✅ Advanced search found ${users.length} users`);
|
||
this.applyFiltersAndPagination();
|
||
this.loading = false;
|
||
this.cdRef.detectChanges();
|
||
},
|
||
error: (error: any) => {
|
||
console.error('❌ Error searching users:', error);
|
||
this.loading = false;
|
||
this.cdRef.detectChanges();
|
||
}
|
||
});
|
||
} else {
|
||
this.loadUsers(); // Recharger tous les utilisateurs si la recherche est vide
|
||
}
|
||
}
|
||
|
||
// Recharger les données
|
||
refreshData() {
|
||
console.log('🔄 Refreshing data...');
|
||
this.loadUsers();
|
||
}
|
||
} |