feat: add DCB User Service API - Authentication system with KEYCLOAK - Modular architecture with services for each feature
This commit is contained in:
parent
296fe413a9
commit
93c5aa33c7
@ -3,9 +3,6 @@ import { VerticalLayout } from '@layouts/vertical-layout/vertical-layout';
|
|||||||
import { authGuard } from './core/guards/auth.guard';
|
import { authGuard } from './core/guards/auth.guard';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
// Redirection racine
|
|
||||||
{ path: '', redirectTo: '/dcb-dashboard', pathMatch: 'full' },
|
|
||||||
|
|
||||||
// ===== ROUTES D'ERREUR (publiques) =====
|
// ===== ROUTES D'ERREUR (publiques) =====
|
||||||
{
|
{
|
||||||
path: 'error',
|
path: 'error',
|
||||||
|
|||||||
@ -66,7 +66,6 @@ export class AuthService {
|
|||||||
private userProfile$ = new BehaviorSubject<User | null>(null);
|
private userProfile$ = new BehaviorSubject<User | null>(null);
|
||||||
private initialized$ = new BehaviorSubject<boolean>(false);
|
private initialized$ = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
private readonly dashboardAccessService = inject(DashboardAccessService);
|
|
||||||
private readonly transactionAccessService = inject(TransactionAccessService);
|
private readonly transactionAccessService = inject(TransactionAccessService);
|
||||||
|
|
||||||
// === INITIALISATION DE L'APPLICATION ===
|
// === INITIALISATION DE L'APPLICATION ===
|
||||||
@ -198,14 +197,14 @@ export class AuthService {
|
|||||||
).pipe(
|
).pipe(
|
||||||
tap(() => {
|
tap(() => {
|
||||||
this.clearAuthData();
|
this.clearAuthData();
|
||||||
this.dashboardAccessService.clearCache();
|
|
||||||
this.transactionAccessService.clearCache();
|
this.transactionAccessService.clearCache();
|
||||||
this.clearAllStorage(); // Nettoyer tout le storage
|
this.clearAllStorage(); // Nettoyer tout le storage
|
||||||
}),
|
}),
|
||||||
catchError(error => {
|
catchError(error => {
|
||||||
// Même en cas d'erreur, nettoyer tout
|
// Même en cas d'erreur, nettoyer tout
|
||||||
this.clearAuthData();
|
this.clearAuthData();
|
||||||
this.dashboardAccessService.clearCache();
|
|
||||||
this.transactionAccessService.clearCache();
|
this.transactionAccessService.clearCache();
|
||||||
this.clearAllStorage();
|
this.clearAllStorage();
|
||||||
console.warn('Logout API error, but local data cleared:', error);
|
console.warn('Logout API error, but local data cleared:', error);
|
||||||
@ -215,7 +214,7 @@ export class AuthService {
|
|||||||
finalize(() => {
|
finalize(() => {
|
||||||
// Garantir le nettoyage dans tous les cas
|
// Garantir le nettoyage dans tous les cas
|
||||||
this.clearAuthData();
|
this.clearAuthData();
|
||||||
this.dashboardAccessService.clearCache();
|
|
||||||
this.transactionAccessService.clearCache();
|
this.transactionAccessService.clearCache();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -226,7 +225,7 @@ export class AuthService {
|
|||||||
*/
|
*/
|
||||||
forceLogout(): void {
|
forceLogout(): void {
|
||||||
this.clearAuthData();
|
this.clearAuthData();
|
||||||
this.dashboardAccessService.clearCache();
|
|
||||||
this.transactionAccessService.clearCache();
|
this.transactionAccessService.clearCache();
|
||||||
this.clearAllStorage();
|
this.clearAllStorage();
|
||||||
}
|
}
|
||||||
@ -236,7 +235,7 @@ export class AuthService {
|
|||||||
*/
|
*/
|
||||||
private clearAuthData(): void {
|
private clearAuthData(): void {
|
||||||
|
|
||||||
this.dashboardAccessService.clearCache();
|
|
||||||
this.transactionAccessService.clearCache();
|
this.transactionAccessService.clearCache();
|
||||||
|
|
||||||
// Supprimer tous les tokens et données utilisateur
|
// Supprimer tous les tokens et données utilisateur
|
||||||
@ -375,6 +374,10 @@ export class AuthService {
|
|||||||
return this.userProfile$.asObservable();
|
return this.userProfile$.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCurrentUserProfile(): User | null {
|
||||||
|
return this.userProfile$.value;
|
||||||
|
}
|
||||||
|
|
||||||
// === GESTION DES RÔLES ET TYPES ===
|
// === GESTION DES RÔLES ET TYPES ===
|
||||||
|
|
||||||
getCurrentUserRoles(): UserRole[] {
|
getCurrentUserRoles(): UserRole[] {
|
||||||
@ -545,10 +548,42 @@ export class AuthService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Récupère le merchantPartnerId de l'utilisateur courant (si marchand)
|
* Récupère le merchantPartnerId de l'utilisateur courant (si marchand)
|
||||||
|
* Retourne string pour compatibilité, mais devrait être converti en number ailleurs
|
||||||
*/
|
*/
|
||||||
getCurrentMerchantPartnerId(): string | null {
|
getCurrentMerchantPartnerId(): string | null {
|
||||||
const profile = this.userProfile$.value;
|
const profile = this.userProfile$.value;
|
||||||
return profile?.merchantPartnerId || null;
|
|
||||||
|
if (!profile) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const merchantId = profile.merchantPartnerId
|
||||||
|
|
||||||
|
if (merchantId === null || merchantId === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return merchantId.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version qui retourne un number (pour usage interne)
|
||||||
|
*/
|
||||||
|
getCurrentMerchantPartnerIdAsNumber(): number | null {
|
||||||
|
const merchantIdStr = this.getCurrentMerchantPartnerId();
|
||||||
|
|
||||||
|
if (!merchantIdStr) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const merchantId = Number(merchantIdStr);
|
||||||
|
|
||||||
|
if (isNaN(merchantId) || merchantId <= 0 || !Number.isInteger(merchantId)) {
|
||||||
|
console.error(`Merchant ID invalide: ${merchantIdStr}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return merchantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -309,62 +309,96 @@ export class DcbReportingDashboard implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
Chart.register(...registerables);
|
Chart.register(...registerables);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.initializeAccess();
|
// 1. Initialiser l'accès
|
||||||
this.loadAllowedMerchants();
|
this.initializeAccess();
|
||||||
|
|
||||||
|
// 2. Initialiser le dashboard (avec délai pour laisser le temps à l'accès)
|
||||||
|
setTimeout(() => {
|
||||||
this.initializeDashboard();
|
this.initializeDashboard();
|
||||||
|
}, 100);
|
||||||
if (this.accessService.shouldShowSystemHealth()) {
|
|
||||||
setInterval(() => {
|
// 3. Charger les merchants (avec délai)
|
||||||
this.checkSystemHealth();
|
setTimeout(() => {
|
||||||
}, 5 * 60 * 1000);
|
this.loadAllowedMerchants();
|
||||||
}
|
}, 150);
|
||||||
|
|
||||||
|
if (this.accessService.shouldShowSystemHealth()) {
|
||||||
|
setInterval(() => {
|
||||||
|
this.checkSystemHealth();
|
||||||
|
}, 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============ INITIALISATION ============
|
// ============ INITIALISATION ============
|
||||||
|
|
||||||
private initializeAccess(): void {
|
private initializeAccess(): void {
|
||||||
this.access = this.accessService.getDashboardAccess();
|
// Attendre que l'accès soit prêt
|
||||||
this.currentRoleLabel = this.access.roleLabel;
|
this.subscriptions.push(
|
||||||
this.currentRoleIcon = this.access.roleIcon;
|
this.accessService.waitForAccess().subscribe(() => {
|
||||||
|
this.access = this.accessService.getDashboardAccess();
|
||||||
|
this.currentRoleLabel = this.access.roleLabel;
|
||||||
|
this.currentRoleIcon = this.access.roleIcon;
|
||||||
|
|
||||||
// Récupérer le merchant ID du service d'accès
|
console.log('✅ Dashboard initialisé avec:', {
|
||||||
const merchantPartnerId = this.getCurrentMerchantPartnerId();
|
access: this.access,
|
||||||
|
merchantId: this.access.merchantId,
|
||||||
|
isHubUser: this.access.isHubUser,
|
||||||
|
});
|
||||||
|
|
||||||
if (this.access.isMerchantUser) {
|
// Pour les merchant users
|
||||||
// Pour les merchant users, vérifier que l'ID est valide
|
if (this.access.isMerchantUser) {
|
||||||
if (merchantPartnerId) {
|
const merchantId = this.access.merchantId;
|
||||||
this.merchantId = Number(merchantPartnerId);
|
|
||||||
this.accessService.setSelectedMerchantId(this.merchantId);
|
if (merchantId && merchantId > 0) {
|
||||||
this.isViewingGlobalData = false;
|
this.merchantId = merchantId;
|
||||||
|
this.accessService.setSelectedMerchantId(merchantId);
|
||||||
console.log(`Merchant User: ID = ${this.merchantId}`);
|
this.isViewingGlobalData = false;
|
||||||
} else {
|
this.dataSelection.merchantPartnerId = merchantId;
|
||||||
console.error('Merchant ID invalide pour Merchant User:', merchantPartnerId);
|
|
||||||
this.addAlert('danger', 'Erreur de configuration',
|
console.log(`✅ Merchant User: ID = ${this.merchantId}`);
|
||||||
'Impossible de déterminer le merchant ID', 'Maintenant');
|
} else {
|
||||||
this.isViewingGlobalData = false;
|
console.error('❌ Merchant ID invalide pour Merchant User:', merchantId);
|
||||||
}
|
// Essayer de récupérer directement depuis le profil
|
||||||
} else if (this.access.isHubUser) {
|
const merchantPartnerId = this.authService.getCurrentMerchantPartnerId();
|
||||||
// Pour les hub users, vérifier si un merchant est sélectionné
|
if (merchantPartnerId) {
|
||||||
const selectedMerchantId = this.accessService.getSelectedMerchantId();
|
const id = Number(merchantPartnerId);
|
||||||
|
if (!isNaN(id) && id > 0) {
|
||||||
if (selectedMerchantId && selectedMerchantId > 0) {
|
this.merchantId = id;
|
||||||
this.merchantId = selectedMerchantId;
|
this.accessService.setSelectedMerchantId(id);
|
||||||
this.isViewingGlobalData = false;
|
this.isViewingGlobalData = false;
|
||||||
console.log(`Hub User: Merchant sélectionné = ${this.merchantId}`);
|
this.dataSelection.merchantPartnerId = id;
|
||||||
} else {
|
console.log(`✅ Merchant ID récupéré depuis profil: ${id}`);
|
||||||
this.isViewingGlobalData = true;
|
}
|
||||||
this.merchantId = undefined;
|
} else {
|
||||||
console.log('Hub User: Mode global (aucun merchant sélectionné)');
|
this.addAlert('danger', 'Erreur de configuration',
|
||||||
}
|
'Impossible de déterminer le merchant ID', 'Maintenant');
|
||||||
}
|
this.isViewingGlobalData = false;
|
||||||
|
}
|
||||||
// Mettre à jour la sélection de données
|
}
|
||||||
this.dataSelection.merchantPartnerId = this.isViewingGlobalData ?
|
}
|
||||||
undefined : this.merchantId;
|
// Pour les hub users
|
||||||
|
else if (this.access.isHubUser) {
|
||||||
|
const selectedMerchantId = this.accessService.getSelectedMerchantId();
|
||||||
|
|
||||||
|
if (selectedMerchantId && selectedMerchantId > 0) {
|
||||||
|
this.merchantId = selectedMerchantId;
|
||||||
|
this.isViewingGlobalData = false;
|
||||||
|
this.dataSelection.merchantPartnerId = selectedMerchantId;
|
||||||
|
console.log(`✅ Hub User: Merchant sélectionné = ${this.merchantId}`);
|
||||||
|
} else {
|
||||||
|
this.isViewingGlobalData = true;
|
||||||
|
this.merchantId = undefined;
|
||||||
|
this.dataSelection.merchantPartnerId = undefined;
|
||||||
|
console.log('✅ Hub User: Mode global (aucun merchant sélectionné)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
isValidMerchantId(id: any): boolean {
|
isValidMerchantId(id: any): boolean {
|
||||||
if (id === null || id === undefined) {
|
if (id === null || id === undefined) {
|
||||||
return false;
|
return false;
|
||||||
@ -390,7 +424,14 @@ export class DcbReportingDashboard implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeDashboard(): void {
|
private initializeDashboard(): void {
|
||||||
|
// Vérifier d'abord si le profil est chargé
|
||||||
|
const profile = this.authService.getProfile();
|
||||||
|
|
||||||
|
if (!profile) {
|
||||||
|
console.log('⏳ Profil non chargé, attente...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.access.isHubUser) {
|
if (this.access.isHubUser) {
|
||||||
if (this.isViewingGlobalData) {
|
if (this.isViewingGlobalData) {
|
||||||
this.loadGlobalData();
|
this.loadGlobalData();
|
||||||
|
|||||||
@ -1,22 +1,16 @@
|
|||||||
import { inject, Injectable, Injector } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of, BehaviorSubject } from 'rxjs';
|
||||||
import { map, catchError } from 'rxjs/operators';
|
import { map, catchError, switchMap, take, filter, first } from 'rxjs/operators';
|
||||||
import { UserRole, RoleManagementService } from '@core/services/hub-users-roles-management.service';
|
import { UserRole, RoleManagementService } from '@core/services/hub-users-roles-management.service';
|
||||||
import { MerchantConfigService } from '@modules/merchant-config/merchant-config.service';
|
import { MerchantConfigService } from '@modules/merchant-config/merchant-config.service';
|
||||||
import { AuthService } from '@core/services/auth.service';
|
import { AuthService } from '@core/services/auth.service';
|
||||||
|
|
||||||
// Interface minimaliste
|
|
||||||
export interface DashboardAccess {
|
export interface DashboardAccess {
|
||||||
// Type d'utilisateur - CORE
|
|
||||||
isHubUser: boolean;
|
isHubUser: boolean;
|
||||||
isMerchantUser: boolean;
|
isMerchantUser: boolean;
|
||||||
|
|
||||||
// Info du rôle
|
|
||||||
roleLabel: string;
|
roleLabel: string;
|
||||||
roleIcon: string;
|
roleIcon: string;
|
||||||
userRole: UserRole;
|
userRole: UserRole;
|
||||||
|
|
||||||
// Merchant info (seulement pour merchant users)
|
|
||||||
merchantId?: number;
|
merchantId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,16 +24,48 @@ export class DashboardAccessService {
|
|||||||
private accessCache: DashboardAccess | null = null;
|
private accessCache: DashboardAccess | null = null;
|
||||||
private merchantsCache: AllowedMerchant[] | null = null;
|
private merchantsCache: AllowedMerchant[] | null = null;
|
||||||
private currentMerchantId: number | null = null;
|
private currentMerchantId: number | null = null;
|
||||||
|
private accessReady$ = new BehaviorSubject<boolean>(false);
|
||||||
private readonly injector = inject(Injector);
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private roleService: RoleManagementService,
|
private roleService: RoleManagementService,
|
||||||
private merchantService: MerchantConfigService
|
private merchantService: MerchantConfigService,
|
||||||
) {}
|
private authService: AuthService
|
||||||
|
) {
|
||||||
|
// S'abonner aux changements du profil utilisateur
|
||||||
|
this.initializeProfileSubscription();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtient l'accès simplifié
|
* Initialise la surveillance du profil utilisateur
|
||||||
|
*/
|
||||||
|
private initializeProfileSubscription(): void {
|
||||||
|
this.authService.getUserProfile().pipe(
|
||||||
|
filter(profile => profile !== null),
|
||||||
|
first()
|
||||||
|
).subscribe(profile => {
|
||||||
|
console.log('📊 DashboardAccessService: Profil utilisateur chargé', {
|
||||||
|
username: profile.username,
|
||||||
|
merchantPartnerId: profile.merchantPartnerId,
|
||||||
|
userType: profile.userType
|
||||||
|
});
|
||||||
|
|
||||||
|
this.clearCache();
|
||||||
|
this.accessReady$.next(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attend que l'accès soit prêt
|
||||||
|
*/
|
||||||
|
waitForAccess(): Observable<boolean> {
|
||||||
|
return this.accessReady$.pipe(
|
||||||
|
filter(ready => ready),
|
||||||
|
take(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient l'accès dashboard (version synchrone)
|
||||||
*/
|
*/
|
||||||
getDashboardAccess(): DashboardAccess {
|
getDashboardAccess(): DashboardAccess {
|
||||||
if (this.accessCache) {
|
if (this.accessCache) {
|
||||||
@ -49,92 +75,174 @@ export class DashboardAccessService {
|
|||||||
const userRole = this.roleService.getCurrentRole();
|
const userRole = this.roleService.getCurrentRole();
|
||||||
const isHubUser = this.roleService.isHubUser();
|
const isHubUser = this.roleService.isHubUser();
|
||||||
|
|
||||||
|
let merchantId: number | undefined = undefined;
|
||||||
|
|
||||||
|
if (!isHubUser) {
|
||||||
|
merchantId = this.getMerchantIdForCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
const access: DashboardAccess = {
|
const access: DashboardAccess = {
|
||||||
isHubUser,
|
isHubUser,
|
||||||
isMerchantUser: !isHubUser,
|
isMerchantUser: !isHubUser,
|
||||||
roleLabel: this.roleService.getRoleLabel(),
|
roleLabel: this.roleService.getRoleLabel(),
|
||||||
roleIcon: this.roleService.getRoleIcon(),
|
roleIcon: this.roleService.getRoleIcon(),
|
||||||
userRole: userRole || UserRole.DCB_SUPPORT,
|
userRole: userRole || UserRole.DCB_SUPPORT,
|
||||||
|
merchantId
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pour les merchant users, définir leur merchant ID
|
console.log('📊 DashboardAccess créé:', {
|
||||||
if (!isHubUser) {
|
...access,
|
||||||
access.merchantId = this.getMerchantIdForUser();
|
merchantId,
|
||||||
}
|
userRoleLabel: userRole
|
||||||
|
});
|
||||||
|
|
||||||
this.accessCache = access;
|
this.accessCache = access;
|
||||||
return access;
|
return access;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtient le merchant ID pour un merchant user
|
* Obtient l'accès dashboard (version asynchrone)
|
||||||
*/
|
*/
|
||||||
private getMerchantIdForUser(): number | undefined {
|
getDashboardAccessAsync(): Observable<DashboardAccess> {
|
||||||
// Récupérer le merchant ID de l'utilisateur courant
|
return this.waitForAccess().pipe(
|
||||||
const authService = this.injector.get(AuthService);
|
map(() => this.getDashboardAccess())
|
||||||
|
);
|
||||||
const merchantPartnerId = authService.getCurrentMerchantPartnerId();
|
|
||||||
|
|
||||||
// Vérifier si la valeur existe et est numérique
|
|
||||||
if (!merchantPartnerId) {
|
|
||||||
console.warn('Aucun merchant ID trouvé pour l\'utilisateur');
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convertir en nombre en gérant les erreurs
|
|
||||||
const merchantId = Number(merchantPartnerId);
|
|
||||||
|
|
||||||
if (isNaN(merchantId) || !Number.isInteger(merchantId)) {
|
|
||||||
console.error(`Merchant ID invalide: ${merchantPartnerId}`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return merchantId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtient les merchants disponibles
|
* Récupère le merchant ID pour l'utilisateur courant
|
||||||
* - Hub users: tous les merchants
|
*/
|
||||||
* - Merchant users: seulement leur merchant
|
private getMerchantIdForCurrentUser(): number | undefined {
|
||||||
|
// Utiliser la méthode optimisée d'AuthService
|
||||||
|
const merchantId = this.authService.getCurrentMerchantPartnerIdAsNumber();
|
||||||
|
|
||||||
|
if (this.isValidMerchantId(merchantId)) {
|
||||||
|
console.log(`✅ Merchant ID récupéré: ${merchantId}`);
|
||||||
|
return merchantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('⚠️ Aucun merchant ID valide trouvé pour l\'utilisateur');
|
||||||
|
console.log('Debug:', {
|
||||||
|
merchantId,
|
||||||
|
profile: this.authService.getCurrentUserProfile(),
|
||||||
|
isAuthenticated: this.authService.isAuthenticated()
|
||||||
|
});
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valide si un ID marchand est valide
|
||||||
|
*/
|
||||||
|
private isValidMerchantId(id: any): id is number {
|
||||||
|
if (id === null || id === undefined) return false;
|
||||||
|
|
||||||
|
const numId = Number(id);
|
||||||
|
return !isNaN(numId) &&
|
||||||
|
Number.isInteger(numId) &&
|
||||||
|
numId > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtient la liste des merchants disponibles
|
||||||
*/
|
*/
|
||||||
getAvailableMerchants(): Observable<AllowedMerchant[]> {
|
getAvailableMerchants(): Observable<AllowedMerchant[]> {
|
||||||
if (this.merchantsCache) {
|
return this.waitForAccess().pipe(
|
||||||
return of(this.merchantsCache);
|
switchMap(() => {
|
||||||
}
|
if (this.merchantsCache) {
|
||||||
|
return of(this.merchantsCache);
|
||||||
|
}
|
||||||
|
|
||||||
const access = this.getDashboardAccess();
|
const access = this.getDashboardAccess();
|
||||||
|
|
||||||
if (access.isHubUser) {
|
console.log('📊 getAvailableMerchants pour:', {
|
||||||
// Hub users voient tous les merchants
|
isHubUser: access.isHubUser,
|
||||||
return this.merchantService.getAllMerchants().pipe(
|
merchantId: access.merchantId,
|
||||||
map(merchants => {
|
role: access.userRole
|
||||||
const availableMerchants: any[] = merchants.map(m => ({
|
});
|
||||||
id: m.id,
|
|
||||||
name: m.name
|
if (access.isHubUser) {
|
||||||
}));
|
// Hub users: tous les merchants + option globale
|
||||||
this.merchantsCache = availableMerchants;
|
return this.loadAllMerchantsForHubUser();
|
||||||
return availableMerchants;
|
} else {
|
||||||
}),
|
// Merchant users: seulement leur merchant
|
||||||
catchError(error => {
|
return this.loadSingleMerchantForUser(access.merchantId);
|
||||||
console.error('Erreur chargement merchants:', error);
|
}
|
||||||
return of([]);
|
})
|
||||||
})
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Merchant users: seulement leur merchant
|
|
||||||
const merchantId = access.merchantId || this.getMerchantIdForUser();
|
|
||||||
return of([{
|
|
||||||
id: merchantId,
|
|
||||||
name: `Merchant ${merchantId}`
|
|
||||||
}]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Définit le merchant sélectionné
|
* Charge tous les merchants pour les hub users
|
||||||
|
*/
|
||||||
|
private loadAllMerchantsForHubUser(): Observable<AllowedMerchant[]> {
|
||||||
|
return this.merchantService.getAllMerchants().pipe(
|
||||||
|
map(merchants => {
|
||||||
|
const availableMerchants: AllowedMerchant[] = merchants.map(m => ({
|
||||||
|
id: m.id,
|
||||||
|
name: m.name
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Ajouter l'option "Global"
|
||||||
|
availableMerchants.unshift({
|
||||||
|
id: 0,
|
||||||
|
name: '🌐 Données globales'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.merchantsCache = availableMerchants;
|
||||||
|
return availableMerchants;
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
console.error('❌ Erreur lors du chargement des merchants:', error);
|
||||||
|
// Retourner au moins l'option globale
|
||||||
|
return of([{
|
||||||
|
id: 0,
|
||||||
|
name: '🌐 Données globales'
|
||||||
|
}]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge le merchant unique pour un merchant user
|
||||||
|
*/
|
||||||
|
private loadSingleMerchantForUser(merchantId?: number): Observable<AllowedMerchant[]> {
|
||||||
|
if (!merchantId || merchantId <= 0) {
|
||||||
|
console.warn('⚠️ Aucun merchant ID valide pour merchant user');
|
||||||
|
|
||||||
|
// Dernière tentative de récupération
|
||||||
|
const fallbackId = this.getMerchantIdForCurrentUser();
|
||||||
|
if (this.isValidMerchantId(fallbackId)) {
|
||||||
|
const merchants = [{
|
||||||
|
id: fallbackId,
|
||||||
|
name: `🏪 Merchant ${fallbackId}`
|
||||||
|
}];
|
||||||
|
this.merchantsCache = merchants;
|
||||||
|
return of(merchants);
|
||||||
|
}
|
||||||
|
|
||||||
|
return of([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const merchants: AllowedMerchant[] = [{
|
||||||
|
id: merchantId,
|
||||||
|
name: `🏪 Merchant ${merchantId}`
|
||||||
|
}];
|
||||||
|
|
||||||
|
this.merchantsCache = merchants;
|
||||||
|
return of(merchants);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit le merchant sélectionné (pour hub users)
|
||||||
*/
|
*/
|
||||||
setSelectedMerchantId(merchantId: number): void {
|
setSelectedMerchantId(merchantId: number): void {
|
||||||
this.currentMerchantId = merchantId;
|
if (this.getDashboardAccess().isHubUser) {
|
||||||
|
this.currentMerchantId = merchantId;
|
||||||
|
console.log(`📌 Merchant sélectionné: ${merchantId}`);
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ Seuls les hub users peuvent sélectionner un merchant');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,7 +256,7 @@ export class DashboardAccessService {
|
|||||||
return access.merchantId || null;
|
return access.merchantId || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hub users: le merchant sélectionné ou le premier
|
// Hub users: le merchant sélectionné
|
||||||
return this.currentMerchantId;
|
return this.currentMerchantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,9 +266,8 @@ export class DashboardAccessService {
|
|||||||
canAccessMerchant(merchantId: number): Observable<boolean> {
|
canAccessMerchant(merchantId: number): Observable<boolean> {
|
||||||
const access = this.getDashboardAccess();
|
const access = this.getDashboardAccess();
|
||||||
|
|
||||||
// Hub users: tous les merchants sont accessibles
|
|
||||||
if (access.isHubUser) {
|
if (access.isHubUser) {
|
||||||
return of(true);
|
return of(true); // Hub users: accès à tous
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merchant users: seulement leur merchant
|
// Merchant users: seulement leur merchant
|
||||||
@ -174,13 +281,30 @@ export class DashboardAccessService {
|
|||||||
this.accessCache = null;
|
this.accessCache = null;
|
||||||
this.merchantsCache = null;
|
this.merchantsCache = null;
|
||||||
this.currentMerchantId = null;
|
this.currentMerchantId = null;
|
||||||
|
console.log('🗑️ DashboardAccessService: Cache nettoyé');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Méthodes utilitaires pour le template
|
* Méthode de débogage
|
||||||
*/
|
*/
|
||||||
|
debug(): void {
|
||||||
// Pour les Hub Users
|
console.log('=== 🔍 DEBUG DashboardAccessService ===');
|
||||||
|
console.log('1. Access cache:', this.accessCache);
|
||||||
|
console.log('2. Merchants cache:', this.merchantsCache);
|
||||||
|
console.log('3. Current merchant ID:', this.currentMerchantId);
|
||||||
|
console.log('4. Access ready:', this.accessReady$.value);
|
||||||
|
|
||||||
|
console.log('5. AuthService info:');
|
||||||
|
console.log(' - Merchant ID (number):', this.authService.getCurrentMerchantPartnerIdAsNumber());
|
||||||
|
console.log(' - Merchant ID (string):', this.authService.getCurrentMerchantPartnerId());
|
||||||
|
console.log(' - Profil courant:', this.authService.getCurrentUserProfile());
|
||||||
|
console.log(' - Token présent:', !!this.authService.getAccessToken());
|
||||||
|
console.log(' - Is authenticated:', this.authService.isAuthenticated());
|
||||||
|
console.log('==============================');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ MÉTHODES UTILITAIRES POUR LE TEMPLATE ============
|
||||||
|
|
||||||
shouldShowSystemHealth(): boolean {
|
shouldShowSystemHealth(): boolean {
|
||||||
return this.getDashboardAccess().isHubUser;
|
return this.getDashboardAccess().isHubUser;
|
||||||
}
|
}
|
||||||
@ -199,40 +323,36 @@ export class DashboardAccessService {
|
|||||||
return access.isHubUser && access.userRole === UserRole.DCB_ADMIN;
|
return access.isHubUser && access.userRole === UserRole.DCB_ADMIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pour tous les utilisateurs
|
|
||||||
shouldShowTransactions(): boolean {
|
shouldShowTransactions(): boolean {
|
||||||
return true; // Tous peuvent voir les transactions (mais scope différent)
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowCharts(): boolean {
|
shouldShowCharts(): boolean {
|
||||||
return true; // Tous peuvent voir les transactions (mais scope différent)
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowKPIs(): boolean {
|
shouldShowKPIs(): boolean {
|
||||||
return true; // Tous peuvent voir les transactions (mais scope différent)
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowAlerts(): boolean {
|
shouldShowAlerts(): boolean {
|
||||||
return true; // Tous peuvent voir les transactions (mais scope différent)
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
canRefreshData(): boolean {
|
canRefreshData(): boolean {
|
||||||
return true; // Tous peuvent rafraîchir
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pour la sélection de merchant
|
|
||||||
canSelectMerchant(): boolean {
|
canSelectMerchant(): boolean {
|
||||||
return this.getDashboardAccess().isHubUser;
|
return this.getDashboardAccess().isHubUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pour l'affichage du merchant ID
|
|
||||||
shouldShowMerchantId(): boolean {
|
shouldShowMerchantId(): boolean {
|
||||||
const access = this.getDashboardAccess();
|
const access = this.getDashboardAccess();
|
||||||
return access.isMerchantUser ||
|
return access.isMerchantUser ||
|
||||||
(access.isHubUser && this.getSelectedMerchantId() !== null);
|
(access.isHubUser && this.getSelectedMerchantId() !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pour l'édition du merchant filter
|
|
||||||
canEditMerchantFilter(): boolean {
|
canEditMerchantFilter(): boolean {
|
||||||
const access = this.getDashboardAccess();
|
const access = this.getDashboardAccess();
|
||||||
if (access.isHubUser) {
|
if (access.isHubUser) {
|
||||||
@ -240,4 +360,55 @@ export class DashboardAccessService {
|
|||||||
}
|
}
|
||||||
return access.userRole === UserRole.DCB_PARTNER_ADMIN;
|
return access.userRole === UserRole.DCB_PARTNER_ADMIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============ MÉTHODES UTILITAIRES SUPPLÉMENTAIRES ============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'utilisateur peut voir les données globales
|
||||||
|
*/
|
||||||
|
canViewGlobalData(): boolean {
|
||||||
|
return this.getDashboardAccess().isHubUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si l'utilisateur est en mode "données globales"
|
||||||
|
*/
|
||||||
|
isViewingGlobalData(): boolean {
|
||||||
|
const access = this.getDashboardAccess();
|
||||||
|
if (access.isHubUser) {
|
||||||
|
return this.currentMerchantId === 0 || this.currentMerchantId === null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le nom du merchant courant
|
||||||
|
*/
|
||||||
|
getCurrentMerchantName(): string {
|
||||||
|
const access = this.getDashboardAccess();
|
||||||
|
|
||||||
|
if (access.isMerchantUser && access.merchantId) {
|
||||||
|
return `Merchant ${access.merchantId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access.isHubUser) {
|
||||||
|
if (this.currentMerchantId === 0 || this.currentMerchantId === null) {
|
||||||
|
return 'Données globales';
|
||||||
|
} else if (this.currentMerchantId) {
|
||||||
|
return `Merchant ${this.currentMerchantId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Inconnu';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Réinitialise complètement le service
|
||||||
|
*/
|
||||||
|
reset(): void {
|
||||||
|
this.clearCache();
|
||||||
|
this.accessReady$.next(false);
|
||||||
|
// Réinitialiser la surveillance du profil
|
||||||
|
this.initializeProfileSubscription();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user