mesauth-angular 0.2.20 → 0.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -116,15 +116,109 @@ class MesAuthService {
|
|
|
116
116
|
deleteNotification(notificationId) {
|
|
117
117
|
return this.http.delete(`${this.apiBase}/notif/${notificationId}`, { withCredentials: this.config?.withCredentials ?? true });
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Get frontend routes assigned to the current user
|
|
121
|
+
* Returns routes grouped by application
|
|
122
|
+
*/
|
|
119
123
|
getFrontEndRoutes() {
|
|
120
124
|
if (!this.apiBase)
|
|
121
125
|
throw new Error('MesAuth not initialized');
|
|
122
126
|
return this.http.get(`${this.apiBase}/fe-routes/me`, { withCredentials: this.config?.withCredentials ?? true });
|
|
123
127
|
}
|
|
124
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Get master routes for a specific application
|
|
130
|
+
* @param appId - The application ID
|
|
131
|
+
*/
|
|
132
|
+
getRouteMasters(appId) {
|
|
125
133
|
if (!this.apiBase)
|
|
126
134
|
throw new Error('MesAuth not initialized');
|
|
127
|
-
return this.http.
|
|
135
|
+
return this.http.get(`${this.apiBase}/fe-routes/masters/${appId}`, { withCredentials: this.config?.withCredentials ?? true });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Register/sync frontend routes for an application
|
|
139
|
+
* This is typically called on app startup to sync routes from the frontend app
|
|
140
|
+
* @param appId - The application ID (passed via X-App-Id header)
|
|
141
|
+
* @param routes - Array of route definitions
|
|
142
|
+
*/
|
|
143
|
+
registerFrontEndRoutes(appId, routes) {
|
|
144
|
+
if (!this.apiBase)
|
|
145
|
+
throw new Error('MesAuth not initialized');
|
|
146
|
+
const headers = { 'X-App-Id': appId };
|
|
147
|
+
return this.http.post(`${this.apiBase}/fe-routes/register`, routes, {
|
|
148
|
+
headers,
|
|
149
|
+
withCredentials: this.config?.withCredentials ?? true
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Create a new route master
|
|
154
|
+
* @param appId - The application ID
|
|
155
|
+
* @param route - Route details
|
|
156
|
+
*/
|
|
157
|
+
createRouteMaster(appId, route) {
|
|
158
|
+
if (!this.apiBase)
|
|
159
|
+
throw new Error('MesAuth not initialized');
|
|
160
|
+
return this.http.post(`${this.apiBase}/fe-routes/masters`, {
|
|
161
|
+
appId,
|
|
162
|
+
...route
|
|
163
|
+
}, { withCredentials: this.config?.withCredentials ?? true });
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Update an existing route master
|
|
167
|
+
* @param routeId - The route master ID
|
|
168
|
+
* @param route - Updated route details
|
|
169
|
+
*/
|
|
170
|
+
updateRouteMaster(routeId, route) {
|
|
171
|
+
if (!this.apiBase)
|
|
172
|
+
throw new Error('MesAuth not initialized');
|
|
173
|
+
return this.http.put(`${this.apiBase}/fe-routes/masters/${routeId}`, route, {
|
|
174
|
+
withCredentials: this.config?.withCredentials ?? true
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Delete a route master
|
|
179
|
+
* @param routeId - The route master ID
|
|
180
|
+
*/
|
|
181
|
+
deleteRouteMaster(routeId) {
|
|
182
|
+
if (!this.apiBase)
|
|
183
|
+
throw new Error('MesAuth not initialized');
|
|
184
|
+
return this.http.delete(`${this.apiBase}/fe-routes/masters/${routeId}`, {
|
|
185
|
+
withCredentials: this.config?.withCredentials ?? true
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Assign a route to a role
|
|
190
|
+
* @param routeMasterId - The route master ID
|
|
191
|
+
* @param roleId - The role ID (GUID)
|
|
192
|
+
*/
|
|
193
|
+
assignRouteToRole(routeMasterId, roleId) {
|
|
194
|
+
if (!this.apiBase)
|
|
195
|
+
throw new Error('MesAuth not initialized');
|
|
196
|
+
return this.http.post(`${this.apiBase}/fe-routes/mappings`, {
|
|
197
|
+
routeMasterId,
|
|
198
|
+
roleId
|
|
199
|
+
}, { withCredentials: this.config?.withCredentials ?? true });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Remove a route assignment from a role
|
|
203
|
+
* @param mappingId - The mapping ID
|
|
204
|
+
*/
|
|
205
|
+
removeRouteFromRole(mappingId) {
|
|
206
|
+
if (!this.apiBase)
|
|
207
|
+
throw new Error('MesAuth not initialized');
|
|
208
|
+
return this.http.delete(`${this.apiBase}/fe-routes/mappings/${mappingId}`, {
|
|
209
|
+
withCredentials: this.config?.withCredentials ?? true
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get route-to-role mappings for a specific role
|
|
214
|
+
* @param roleId - The role ID (GUID)
|
|
215
|
+
*/
|
|
216
|
+
getRouteMappingsByRole(roleId) {
|
|
217
|
+
if (!this.apiBase)
|
|
218
|
+
throw new Error('MesAuth not initialized');
|
|
219
|
+
return this.http.get(`${this.apiBase}/fe-routes/mappings?roleId=${roleId}`, {
|
|
220
|
+
withCredentials: this.config?.withCredentials ?? true
|
|
221
|
+
});
|
|
128
222
|
}
|
|
129
223
|
startConnection(config) {
|
|
130
224
|
if (this.hubConnection)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesauth-angular.mjs","sources":["../../src/mes-auth.service.ts","../../src/mes-auth.interceptor.ts","../../src/mes-auth.module.ts","../../src/theme.service.ts","../../src/user-profile.component.ts","../../src/toast.service.ts","../../src/toast-container.component.ts","../../src/notification-panel.component.ts","../../src/ma-user.component.ts","../../src/notification-badge.component.ts","../../src/mesauth-angular.ts"],"sourcesContent":["import { inject, Injectable } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';\r\nimport { BehaviorSubject, Subject, Observable } from 'rxjs';\r\nimport { tap, filter, debounceTime } from 'rxjs/operators';\r\nimport { Router, NavigationEnd } from '@angular/router';\r\n\r\nexport interface MesAuthConfig { \r\n apiBaseUrl: string;\r\n withCredentials?: boolean;\r\n userBaseUrl?: string;\r\n}\r\n\r\nexport interface IUser {\r\n userId?: string;\r\n userName?: string;\r\n fullName?: string;\r\n gender?: string;\r\n email?: string;\r\n phoneNumber?: string;\r\n department?: string;\r\n position?: string;\r\n tokenVersion?: string;\r\n permEndpoint?: string;\r\n perms?: Set<string>;\r\n employeeCode?: string;\r\n hrFullNameVn?: string;\r\n hrFullNameEn?: string;\r\n hrPosition?: string;\r\n hrJobTitle?: string;\r\n hrGender?: string;\r\n hrMobile?: string;\r\n hrEmail?: string;\r\n hrJoinDate?: string;\r\n hrBirthDate?: string;\r\n hrWorkStatus?: string;\r\n hrDoiTuong?: string;\r\n hrTeamCode?: string;\r\n hrLineCode?: string;\r\n}\r\n\r\nexport enum NotificationType {\r\n Info = 'Info',\r\n Warning = 'Warning',\r\n Error = 'Error',\r\n Success = 'Success'\r\n}\r\n\r\nexport interface NotificationDto {\r\n id: string;\r\n title: string;\r\n message: string;\r\n messageHtml?: string;\r\n url?: string;\r\n type: NotificationType;\r\n isRead: boolean;\r\n createdAt: string;\r\n sourceAppName: string;\r\n sourceAppIconUrl?: string;\r\n}\r\n\r\nexport interface FrontEndRoute {\r\n id: number;\r\n appId: string;\r\n roleId: string;\r\n routePath: string;\r\n routeName: string;\r\n description?: string;\r\n isActive: boolean;\r\n createdAt: string;\r\n updatedAt?: string;\r\n feUrl?: string;\r\n}\r\n\r\nexport interface PagedList<T> {\r\n items: T[];\r\n totalCount: number;\r\n page: number;\r\n pageSize: number;\r\n totalPages: number;\r\n hasNext: boolean;\r\n hasPrevious: boolean;\r\n}\r\n\r\nexport interface RealTimeNotificationDto {\r\n id: string;\r\n title: string;\r\n message: string;\r\n messageHtml?: string;\r\n url?: string;\r\n type: NotificationType;\r\n createdAt: string;\r\n sourceAppName: string;\r\n sourceAppIconUrl?: string;\r\n}\r\n\r\n@Injectable()\r\nexport class MesAuthService {\r\n private hubConnection: HubConnection | null = null;\r\n private _currentUser = new BehaviorSubject<IUser | null>(null);\r\n public currentUser$: Observable<IUser | null> = this._currentUser.asObservable();\r\n private _notifications = new Subject<any>();\r\n public notifications$: Observable<any> = this._notifications.asObservable();\r\n\r\n private apiBase = '';\r\n private config: MesAuthConfig | null = null;\r\n private http!: HttpClient;\r\n private router?: Router;\r\n\r\n constructor() {\r\n // Empty constructor - all dependencies passed to init()\r\n }\r\n\r\n private isProtectedRoute(url: string): boolean {\r\n // Consider routes protected if they don't include auth-related paths\r\n return !url.includes('/login') && !url.includes('/auth') && !url.includes('/signin') && !url.includes('/logout');\r\n }\r\n\r\n init(config: MesAuthConfig, httpClient: HttpClient, router?: Router) {\r\n this.config = config;\r\n this.http = httpClient;\r\n this.router = router;\r\n this.apiBase = config.apiBaseUrl.replace(/\\/$/, '');\r\n\r\n // Listen for route changes - only refresh user data if needed for SPA navigation\r\n // This helps maintain authentication state in single-page applications\r\n if (this.router) {\r\n this.router.events\r\n .pipe(\r\n filter(event => event instanceof NavigationEnd),\r\n debounceTime(1000) // Longer debounce to avoid interfering with login flow\r\n )\r\n .subscribe((event: NavigationEnd) => {\r\n // Only refresh if user is logged in and navigating to protected routes\r\n // Avoid refreshing during login/logout flows\r\n if (this._currentUser.value && this.isProtectedRoute(event.url)) {\r\n // Small delay to ensure any login/logout operations complete\r\n setTimeout(() => {\r\n if (this._currentUser.value) {\r\n this.refreshUser();\r\n }\r\n }, 100);\r\n }\r\n });\r\n }\r\n\r\n this.fetchCurrentUser();\r\n this.fetchInitialNotifications();\r\n }\r\n\r\n getConfig(): MesAuthConfig | null {\r\n return this.config;\r\n }\r\n\r\n private fetchCurrentUser() {\r\n if (!this.apiBase) return;\r\n const url = `${this.apiBase}/auth/me`;\r\n this.http.get(url, { withCredentials: this.config?.withCredentials ?? true }).subscribe({\r\n next: (u) => {\r\n this._currentUser.next(u);\r\n if (u && this.config) {\r\n this.startConnection(this.config);\r\n }\r\n },\r\n error: (err) => {\r\n // Silently handle auth errors (401/403) - user is not logged in\r\n if (err.status === 401 || err.status === 403) {\r\n this._currentUser.next(null);\r\n }\r\n }\r\n });\r\n }\r\n\r\n private fetchInitialNotifications() {\r\n if (!this.apiBase) return;\r\n this.http.get(`${this.apiBase}/notif/me`, { withCredentials: this.config?.withCredentials ?? true }).subscribe({\r\n next: (notifications: any) => {\r\n if (Array.isArray(notifications?.items)) {\r\n notifications.items.forEach((n: any) => this._notifications.next(n));\r\n }\r\n },\r\n error: (err) => {\r\n // Silently handle auth errors (401/403) - user is not logged in\r\n // No need to emit anything\r\n }\r\n });\r\n }\r\n\r\n public getUnreadCount(): Observable<any> {\r\n return this.http.get(`${this.apiBase}/notif/me/unread-count`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public getNotifications(page: number = 1, pageSize: number = 20, includeRead: boolean = false, type?: string): Observable<any> {\r\n let url = `${this.apiBase}/notif/me?page=${page}&pageSize=${pageSize}&includeRead=${includeRead}`;\r\n if (type) {\r\n url += `&type=${type}`;\r\n }\r\n return this.http.get(url, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public markAsRead(notificationId: string): Observable<any> {\r\n return this.http.patch(`${this.apiBase}/notif/${notificationId}/read`, {}, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public markAllAsRead(): Observable<any> {\r\n return this.http.patch(`${this.apiBase}/notif/me/read-all`, {}, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public deleteNotification(notificationId: string): Observable<any> {\r\n return this.http.delete(`${this.apiBase}/notif/${notificationId}`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public getFrontEndRoutes(): Observable<FrontEndRoute[]> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.get<FrontEndRoute[]>(`${this.apiBase}/fe-routes/me`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public registerFrontEndRoutes(routes: any[]): Observable<any> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.post(`${this.apiBase}/fe-routes/register`, routes, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n private startConnection(config: MesAuthConfig) {\r\n if (this.hubConnection) return;\r\n const signalrUrl = config.apiBaseUrl.replace(/\\/$/, '') + '/hub/notification';\r\n const builder = new HubConnectionBuilder()\r\n .withUrl(signalrUrl, { withCredentials: config.withCredentials ?? true })\r\n .withAutomaticReconnect()\r\n .configureLogging(LogLevel.Warning);\r\n\r\n this.hubConnection = builder.build();\r\n\r\n this.hubConnection.on('ReceiveNotification', (n: any) => {\r\n this._notifications.next(n);\r\n });\r\n\r\n this.hubConnection.start().then(() => {}).catch((err) => {});\r\n\r\n this.hubConnection.onclose(() => {});\r\n this.hubConnection.onreconnecting(() => {});\r\n this.hubConnection.onreconnected(() => {});\r\n }\r\n\r\n public stop() {\r\n if (!this.hubConnection) return;\r\n this.hubConnection.stop().catch(() => {});\r\n this.hubConnection = null;\r\n }\r\n\r\n public logout(): Observable<any> {\r\n const url = `${this.apiBase}/auth/logout`;\r\n return this.http.post(url, {}, { withCredentials: this.config?.withCredentials ?? true }).pipe(\r\n tap(() => {\r\n this._currentUser.next(null);\r\n this.stop();\r\n })\r\n );\r\n }\r\n\r\n public refreshUser() {\r\n this.fetchCurrentUser();\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\nimport { MesAuthService } from './mes-auth.service';\r\n\r\n@Injectable()\r\nexport class MesAuthInterceptor implements HttpInterceptor {\r\n constructor(private authService: MesAuthService, private router: Router) {}\r\n\r\n intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n return next.handle(req).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n if (error.status === 403) {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n\r\n // Use router URL for internal navigation (cleaner URLs)\r\n // Falls back to window.location for full URL if needed\r\n const currentUrl = this.router.url || window.location.pathname + window.location.search;\r\n const returnUrl = encodeURIComponent(currentUrl);\r\n\r\n window.location.href = `${baseUrl}/403?returnUrl=${returnUrl}`;\r\n }\r\n return throwError(error);\r\n })\r\n );\r\n }\r\n}\r\n","import { NgModule } from '@angular/core';\r\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { MesAuthService } from './mes-auth.service';\r\nimport { MesAuthInterceptor } from './mes-auth.interceptor';\r\n\r\n@NgModule({\r\n providers: [\r\n MesAuthService,\r\n { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }\r\n ]\r\n})\r\nexport class MesAuthModule {}\r\n","import { Injectable, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\n\r\nexport type Theme = 'light' | 'dark';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class ThemeService implements OnDestroy {\r\n private _currentTheme = new BehaviorSubject<Theme>('light');\r\n public currentTheme$: Observable<Theme> = this._currentTheme.asObservable();\r\n private observer: MutationObserver | null = null;\r\n\r\n constructor() {\r\n this.detectTheme();\r\n this.startWatching();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.stopWatching();\r\n }\r\n\r\n private detectTheme(): void {\r\n const html = document.documentElement;\r\n const isDark = html.classList.contains('dark') ||\r\n html.getAttribute('data-theme') === 'dark' ||\r\n html.getAttribute('theme') === 'dark' ||\r\n html.getAttribute('data-coreui-theme') === 'dark';\r\n\r\n this._currentTheme.next(isDark ? 'dark' : 'light');\r\n }\r\n\r\n private startWatching(): void {\r\n if (typeof MutationObserver === 'undefined') {\r\n // Fallback for older browsers - check periodically\r\n setInterval(() => this.detectTheme(), 1000);\r\n return;\r\n }\r\n\r\n this.observer = new MutationObserver(() => {\r\n this.detectTheme();\r\n });\r\n\r\n this.observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class', 'data-theme', 'theme', 'data-coreui-theme']\r\n });\r\n }\r\n\r\n private stopWatching(): void {\r\n if (this.observer) {\r\n this.observer.disconnect();\r\n this.observer = null;\r\n }\r\n }\r\n\r\n get currentTheme(): Theme {\r\n return this._currentTheme.value;\r\n }\r\n\r\n // Method to manually set theme if needed\r\n setTheme(theme: Theme): void {\r\n this._currentTheme.next(theme);\r\n }\r\n\r\n // Re-detect theme from DOM\r\n refreshTheme(): void {\r\n this.detectTheme();\r\n }\r\n}","import { Component, OnInit, OnDestroy, Output, EventEmitter, HostBinding, HostListener } from '@angular/core';\r\nimport { NgIf } from '@angular/common';\r\nimport { Router } from '@angular/router';\r\nimport { MesAuthService, IUser } from './mes-auth.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-user-profile',\r\n standalone: true,\r\n imports: [NgIf],\r\n template: `\r\n <div class=\"user-profile-container\">\r\n <!-- Not logged in -->\r\n <ng-container *ngIf=\"!currentUser\">\r\n <button class=\"login-btn\" (click)=\"onLogin()\">\r\n Login\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Logged in -->\r\n <ng-container *ngIf=\"currentUser\">\r\n <div class=\"user-header\">\r\n <button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"unreadCount > 0\">{{ unreadCount }}</span>\r\n </button>\r\n\r\n <div class=\"user-menu-wrapper\">\r\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\">\r\n <img \r\n *ngIf=\"currentUser.fullName || currentUser.userName\"\r\n [src]=\"getAvatarUrl(currentUser)\" \r\n [alt]=\"currentUser.fullName || currentUser.userName\"\r\n class=\"avatar\"\r\n />\r\n <span *ngIf=\"!(currentUser.fullName || currentUser.userName)\" class=\"avatar-initial\">\r\n {{ getLastNameInitial(currentUser) }}\r\n </span>\r\n </button>\r\n\r\n <div class=\"mes-dropdown-menu\" *ngIf=\"dropdownOpen\">\r\n <div class=\"mes-dropdown-header\">\r\n {{ currentUser.fullName || currentUser.userName }}\r\n </div>\r\n <button class=\"mes-dropdown-item profile-link\" (click)=\"onViewProfile()\">\r\n View Profile\r\n </button>\r\n <button class=\"mes-dropdown-item logout-item\" (click)=\"onLogout()\">\r\n Logout\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --primary-color: #1976d2;\r\n --primary-hover: #1565c0;\r\n --primary-light: rgba(25, 118, 210, 0.1);\r\n --error-color: #f44336;\r\n --error-light: #ffebee;\r\n --text-primary: #333;\r\n --text-secondary: #666;\r\n --text-muted: #999;\r\n --bg-primary: white;\r\n --bg-secondary: #f5f5f5;\r\n --bg-tertiary: #fafafa;\r\n --bg-hover: #f5f5f5;\r\n --border-color: #e0e0e0;\r\n --border-light: #f0f0f0;\r\n --shadow: rgba(0, 0, 0, 0.15);\r\n --shadow-light: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --primary-color: #90caf9;\r\n --primary-hover: #64b5f6;\r\n --primary-light: rgba(144, 202, 249, 0.1);\r\n --error-color: #ef5350;\r\n --error-light: rgba(239, 83, 80, 0.1);\r\n --text-primary: #e0e0e0;\r\n --text-secondary: #b0b0b0;\r\n --text-muted: #888;\r\n --bg-primary: #1e1e1e;\r\n --bg-secondary: #2d2d2d;\r\n --bg-tertiary: #252525;\r\n --bg-hover: #333;\r\n --border-color: #404040;\r\n --border-light: #333;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n --shadow-light: rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n .user-profile-container {\r\n display: flex;\r\n align-items: center;\r\n gap: 16px;\r\n padding: 0 16px;\r\n }\r\n\r\n .login-btn {\r\n padding: 8px 16px;\r\n background-color: var(--primary-color);\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-weight: 500;\r\n transition: background-color 0.3s;\r\n }\r\n\r\n .login-btn:hover {\r\n background-color: var(--primary-hover);\r\n }\r\n\r\n .user-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 16px;\r\n }\r\n\r\n .notification-btn {\r\n position: relative;\r\n background: none;\r\n border: none;\r\n font-size: 24px;\r\n cursor: pointer;\r\n padding: 8px;\r\n transition: opacity 0.2s;\r\n }\r\n\r\n .notification-btn:hover {\r\n opacity: 0.7;\r\n }\r\n\r\n .icon {\r\n display: inline-block;\r\n }\r\n\r\n .badge {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n background-color: var(--error-color);\r\n color: white;\r\n border-radius: 50%;\r\n width: 20px;\r\n height: 20px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n font-weight: bold;\r\n }\r\n\r\n .user-menu-wrapper {\r\n position: relative;\r\n }\r\n\r\n .user-menu-btn {\r\n background: none;\r\n border: none;\r\n cursor: pointer;\r\n padding: 4px;\r\n border-radius: 50%;\r\n transition: background-color 0.2s;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n\r\n .user-menu-btn:hover {\r\n background-color: var(--primary-light);\r\n }\r\n\r\n .avatar {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 50%;\r\n object-fit: cover;\r\n background-color: #e0e0e0;\r\n }\r\n\r\n .avatar-initial {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 50%;\r\n background-color: var(--primary-color);\r\n color: white;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-weight: bold;\r\n font-size: 16px;\r\n }\r\n\r\n .mes-dropdown-menu {\r\n position: absolute;\r\n top: calc(100% + 8px);\r\n right: 0;\r\n background: var(--bg-primary);\r\n border: 1px solid var(--border-color);\r\n border-radius: 4px;\r\n box-shadow: 0 2px 8px var(--shadow);\r\n min-width: 200px;\r\n z-index: 1000;\r\n overflow: hidden;\r\n }\r\n\r\n .mes-dropdown-header {\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--border-light);\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n font-size: 14px;\r\n }\r\n\r\n .mes-dropdown-item {\r\n display: block;\r\n width: 100%;\r\n padding: 12px 16px;\r\n border: none;\r\n background: none;\r\n text-align: left;\r\n cursor: pointer;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n text-decoration: none;\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .mes-dropdown-item:hover {\r\n background-color: var(--bg-hover);\r\n }\r\n\r\n .profile-link {\r\n color: var(--primary-color);\r\n }\r\n\r\n .logout-item {\r\n border-top: 1px solid var(--border-light);\r\n color: var(--error-color);\r\n }\r\n\r\n .logout-item:hover {\r\n background-color: var(--error-light);\r\n }\r\n\r\n .user-info {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n .user-name {\r\n font-weight: 500;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n }\r\n\r\n .user-position {\r\n font-size: 12px;\r\n color: var(--text-secondary);\r\n }\r\n\r\n .logout-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n padding: 4px 8px;\r\n transition: color 0.2s;\r\n }\r\n\r\n .logout-btn:hover {\r\n color: var(--primary-color);\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .user-info {\r\n display: none;\r\n }\r\n\r\n .avatar {\r\n width: 32px;\r\n height: 32px;\r\n }\r\n }\r\n `]\r\n})\r\nexport class UserProfileComponent implements OnInit, OnDestroy {\r\n @Output() notificationClick = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n currentUser: IUser | null = null;\r\n currentTheme: Theme = 'light';\r\n unreadCount = 0;\r\n dropdownOpen = false;\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private authService: MesAuthService, private router: Router, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.authService.currentUser$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(user => {\r\n this.currentUser = user;\r\n });\r\n\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadUnreadCount();\r\n\r\n // Listen for new notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(() => {\r\n console.log('Notification received, updating unread count');\r\n this.loadUnreadCount();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n loadUnreadCount() {\r\n this.authService.getUnreadCount().subscribe({\r\n next: (response: any) => {\r\n this.unreadCount = response.unreadCount || 0;\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n getAvatarUrl(user: IUser): string {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.apiBaseUrl || '';\r\n \r\n // Use userId for the avatar endpoint\r\n const userId = user.userId;\r\n if (userId && baseUrl) {\r\n return `${baseUrl.replace(/\\/$/, '')}/auth/${userId}/avatar`;\r\n }\r\n \r\n // Fallback to UI avatars service if no userId or baseUrl\r\n const displayName = user.userName || user.userId || 'User';\r\n return `https://ui-avatars.com/api/?name=${encodeURIComponent(displayName)}&background=1976d2&color=fff`;\r\n }\r\n\r\n getLastNameInitial(user: IUser): string {\r\n const fullName = user.fullName || user.userName || 'U';\r\n const parts = fullName.split(' ');\r\n const lastPart = parts[parts.length - 1];\r\n return lastPart.charAt(0).toUpperCase();\r\n }\r\n\r\n toggleDropdown() {\r\n this.dropdownOpen = !this.dropdownOpen;\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: Event) {\r\n const target = event.target as HTMLElement;\r\n const clickedInside = target.closest('.user-menu-wrapper');\r\n if (!clickedInside) {\r\n this.dropdownOpen = false;\r\n }\r\n }\r\n\r\n onLogin() {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n const returnUrl = encodeURIComponent(this.router.url);\r\n window.location.href = `${baseUrl}/login?returnUrl=${returnUrl}`;\r\n }\r\n\r\n onViewProfile() {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n window.location.href = `${baseUrl}/profile`;\r\n this.dropdownOpen = false;\r\n }\r\n\r\n onLogout() {\r\n this.authService.logout().subscribe({\r\n next: () => {\r\n // Clear current user after successful logout\r\n this.dropdownOpen = false;\r\n \r\n // Navigate to login with return URL\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n const returnUrl = encodeURIComponent(window.location.href);\r\n window.location.href = `${baseUrl}/login?returnUrl=${returnUrl}`;\r\n },\r\n error: (err) => {\r\n // Still navigate to login even if logout fails\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n window.location.href = `${baseUrl}/login`;\r\n }\r\n });\r\n }\r\n\r\n onNotificationClick() {\r\n this.notificationClick.emit();\r\n }\r\n}\r\n\r\n","import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\n\r\nexport interface Toast {\r\n id: string;\r\n message: string;\r\n title?: string;\r\n type: 'info' | 'success' | 'warning' | 'error';\r\n duration?: number;\r\n}\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class ToastService {\r\n private toasts$ = new BehaviorSubject<Toast[]>([]);\r\n public toasts: Observable<Toast[]> = this.toasts$.asObservable();\r\n\r\n show(message: string, title?: string, type: 'info' | 'success' | 'warning' | 'error' = 'info', duration: number = 5000) {\r\n const id = Math.random().toString(36).substr(2, 9);\r\n const toast: Toast = {\r\n id,\r\n message,\r\n title,\r\n type,\r\n duration\r\n };\r\n\r\n const currentToasts = this.toasts$.value;\r\n this.toasts$.next([...currentToasts, toast]);\r\n\r\n if (duration > 0) {\r\n setTimeout(() => {\r\n this.remove(id);\r\n }, duration);\r\n }\r\n\r\n return id;\r\n }\r\n\r\n remove(id: string) {\r\n const currentToasts = this.toasts$.value;\r\n this.toasts$.next(currentToasts.filter(t => t.id !== id));\r\n }\r\n\r\n clear() {\r\n this.toasts$.next([]);\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, HostBinding } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { ToastService, Toast } from './toast.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-toast-container',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"toast-container\">\r\n <div \r\n *ngFor=\"let toast of toasts\"\r\n class=\"toast\"\r\n [class]=\"'toast-' + toast.type\"\r\n [@slideIn]\r\n >\r\n <div class=\"toast-content\">\r\n <div *ngIf=\"toast.title\" class=\"toast-title\">{{ toast.title }}</div>\r\n <div class=\"toast-message\" [innerHTML]=\"toast.message\"></div>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"close(toast.id)\" aria-label=\"Close\">\r\n ✕\r\n </button>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --info-color: #2196f3;\r\n --success-color: #4caf50;\r\n --warning-color: #ff9800;\r\n --error-color: #f44336;\r\n --text-primary: #333;\r\n --bg-primary: white;\r\n --shadow: rgba(0, 0, 0, 0.15);\r\n --text-secondary: #999;\r\n --border-color: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --info-color: #64b5f6;\r\n --success-color: #81c784;\r\n --warning-color: #ffb74d;\r\n --error-color: #ef5350;\r\n --text-primary: #e0e0e0;\r\n --bg-primary: #1e1e1e;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n --text-secondary: #888;\r\n --border-color: rgba(255, 255, 255, 0.1);\r\n }\r\n\r\n .toast-container {\r\n position: fixed;\r\n top: 20px;\r\n right: 20px;\r\n z-index: 9999;\r\n pointer-events: none;\r\n }\r\n\r\n .toast {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 12px;\r\n padding: 12px 16px;\r\n margin-bottom: 12px;\r\n border-radius: 4px;\r\n background: var(--bg-primary);\r\n border: 1px solid var(--border-color);\r\n box-shadow: 0 4px 12px var(--shadow);\r\n pointer-events: auto;\r\n min-width: 280px;\r\n max-width: 400px;\r\n animation: slideIn 0.3s ease-out;\r\n }\r\n\r\n .toast-content {\r\n flex: 1;\r\n }\r\n\r\n .toast-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n margin-bottom: 4px;\r\n }\r\n\r\n .toast-message {\r\n font-size: 13px;\r\n line-height: 1.4;\r\n }\r\n\r\n .toast-close {\r\n background: none;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 18px;\r\n color: var(--text-secondary);\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .toast-close:hover {\r\n color: var(--text-primary);\r\n }\r\n\r\n /* Toast types */\r\n .toast-info {\r\n border-left: 4px solid var(--info-color);\r\n }\r\n\r\n .toast-info .toast-title {\r\n color: var(--info-color);\r\n }\r\n\r\n .toast-info .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-success {\r\n border-left: 4px solid var(--success-color);\r\n }\r\n\r\n .toast-success .toast-title {\r\n color: var(--success-color);\r\n }\r\n\r\n .toast-success .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-warning {\r\n border-left: 4px solid var(--warning-color);\r\n }\r\n\r\n .toast-warning .toast-title {\r\n color: var(--warning-color);\r\n }\r\n\r\n .toast-warning .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-error {\r\n border-left: 4px solid var(--error-color);\r\n }\r\n\r\n .toast-error .toast-title {\r\n color: var(--error-color);\r\n }\r\n\r\n .toast-error .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n @keyframes slideIn {\r\n from {\r\n transform: translateX(400px);\r\n opacity: 0;\r\n }\r\n to {\r\n transform: translateX(0);\r\n opacity: 1;\r\n }\r\n }\r\n\r\n @media (max-width: 600px) {\r\n .toast-container {\r\n top: 10px;\r\n right: 10px;\r\n left: 10px;\r\n }\r\n\r\n .toast {\r\n min-width: auto;\r\n max-width: 100%;\r\n }\r\n }\r\n `]\r\n})\r\nexport class ToastContainerComponent implements OnInit, OnDestroy {\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n toasts: Toast[] = [];\r\n currentTheme: Theme = 'light';\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private toastService: ToastService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.toastService.toasts\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(toasts => {\r\n this.toasts = toasts;\r\n });\r\n\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n close(id: string) {\r\n this.toastService.remove(id);\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, HostBinding, Output, EventEmitter } from '@angular/core';\r\nimport { NgIf, NgFor } from '@angular/common';\r\nimport { MesAuthService, NotificationDto, PagedList, RealTimeNotificationDto } from './mes-auth.service';\r\nimport { ToastService } from './toast.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-notification-panel',\r\n standalone: true,\r\n imports: [NgIf, NgFor],\r\n template: `\r\n <div class=\"notification-panel\" [class.open]=\"isOpen\">\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <h3>Notifications</h3>\r\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\">✕</button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button \r\n class=\"tab-btn\" \r\n [class.active]=\"activeTab === 'unread'\"\r\n (click)=\"switchTab('unread')\"\r\n >\r\n Unread ({{ unreadNotifications.length }})\r\n </button>\r\n <button \r\n class=\"tab-btn\" \r\n [class.active]=\"activeTab === 'read'\"\r\n (click)=\"switchTab('read')\"\r\n >\r\n Read ({{ readNotifications.length }})\r\n </button>\r\n </div>\r\n\r\n <!-- Notifications List -->\r\n <div class=\"notifications-list\">\r\n <ng-container *ngIf=\"currentNotifications.length > 0\">\r\n <div \r\n *ngFor=\"let notification of currentNotifications\"\r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.isRead\"\r\n (click)=\"markAsRead(notification.id)\"\r\n >\r\n <div class=\"notification-content\">\r\n <div class=\"notification-title\">{{ notification.title }}</div>\r\n <div class=\"notification-message\" [innerHTML]=\"getNotificationMessage(notification)\"></div>\r\n <div class=\"notification-meta\">\r\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\r\n <span class=\"time\">{{ formatDate(notification.createdAt) }}</span>\r\n </div>\r\n </div>\r\n <button \r\n class=\"read-btn\" \r\n (click)=\"markAsRead(notification.id, $event)\"\r\n title=\"Mark as read\"\r\n *ngIf=\"!notification.isRead\"\r\n >\r\n ✓\r\n </button>\r\n <button \r\n class=\"delete-btn\" \r\n (click)=\"delete(notification.id, $event)\"\r\n title=\"Delete notification\"\r\n *ngIf=\"notification.isRead\"\r\n >\r\n ✓\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"currentNotifications.length === 0\">\r\n <div class=\"empty-state\">\r\n No {{ activeTab }} notifications\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"panel-footer\" *ngIf=\"currentNotifications.length > 0\">\r\n <div class=\"footer-actions\" *ngIf=\"activeTab === 'unread'\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadNotifications.length > 0\">\r\n Mark all as read\r\n </button>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\" *ngIf=\"unreadNotifications.length > 0\">\r\n Delete all\r\n </button>\r\n </div>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\" *ngIf=\"activeTab === 'read' && readNotifications.length > 0\">\r\n Delete all\r\n </button>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --primary-color: #1976d2;\r\n --primary-hover: #1565c0;\r\n --success-color: #4caf50;\r\n --error-color: #f44336;\r\n --text-primary: #333;\r\n --text-secondary: #666;\r\n --text-muted: #999;\r\n --bg-primary: white;\r\n --bg-secondary: #f5f5f5;\r\n --bg-tertiary: #fafafa;\r\n --bg-hover: #f5f5f5;\r\n --bg-unread: #e3f2fd;\r\n --border-color: #e0e0e0;\r\n --border-light: #f0f0f0;\r\n --shadow: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --primary-color: #90caf9;\r\n --primary-hover: #64b5f6;\r\n --success-color: #81c784;\r\n --error-color: #ef5350;\r\n --text-primary: #e0e0e0;\r\n --text-secondary: #b0b0b0;\r\n --text-muted: #888;\r\n --bg-primary: #1e1e1e;\r\n --bg-secondary: #2d2d2d;\r\n --bg-tertiary: #252525;\r\n --bg-hover: #333;\r\n --bg-unread: rgba(144, 202, 249, 0.1);\r\n --border-color: #404040;\r\n --border-light: #333;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n }\r\n\r\n .notification-panel {\r\n position: fixed;\r\n top: 0;\r\n right: -350px;\r\n width: 350px;\r\n height: 100vh;\r\n background: var(--bg-primary);\r\n box-shadow: -2px 0 8px var(--shadow);\r\n display: flex;\r\n flex-direction: column;\r\n z-index: 1000;\r\n transition: right 0.3s ease;\r\n }\r\n\r\n .notification-panel.open {\r\n right: 0;\r\n }\r\n\r\n .panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 16px;\r\n border-bottom: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .panel-header h3 {\r\n margin: 0;\r\n font-size: 18px;\r\n color: var(--text-primary);\r\n }\r\n\r\n .close-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n padding: 0;\r\n width: 32px;\r\n height: 32px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: color 0.2s;\r\n }\r\n\r\n .close-btn:hover {\r\n color: var(--text-primary);\r\n }\r\n\r\n .tabs {\r\n display: flex;\r\n border-bottom: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .tab-btn {\r\n flex: 1;\r\n padding: 12px 16px;\r\n background: none;\r\n border: none;\r\n color: var(--text-secondary);\r\n cursor: pointer;\r\n font-size: 14px;\r\n font-weight: 500;\r\n transition: all 0.2s;\r\n border-bottom: 2px solid transparent;\r\n }\r\n\r\n .tab-btn:hover {\r\n background-color: var(--bg-hover);\r\n color: var(--text-primary);\r\n }\r\n\r\n .tab-btn.active {\r\n color: var(--primary-color);\r\n border-bottom-color: var(--primary-color);\r\n background-color: var(--bg-primary);\r\n }\r\n\r\n .notifications-list {\r\n flex: 1;\r\n overflow-y: auto;\r\n }\r\n\r\n .notification-item {\r\n display: flex;\r\n gap: 12px;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--border-light);\r\n cursor: pointer;\r\n background-color: var(--bg-tertiary);\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .notification-item:hover {\r\n background-color: var(--bg-hover);\r\n }\r\n\r\n .notification-item.unread {\r\n background-color: var(--bg-unread);\r\n }\r\n\r\n .notification-content {\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .notification-title {\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n font-size: 14px;\r\n margin-bottom: 4px;\r\n }\r\n\r\n .notification-message {\r\n color: var(--text-secondary);\r\n font-size: 13px;\r\n line-height: 1.4;\r\n margin-bottom: 6px;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 2;\r\n -webkit-box-orient: vertical;\r\n overflow: hidden;\r\n }\r\n\r\n .notification-meta {\r\n display: flex;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n color: var(--text-muted);\r\n }\r\n\r\n .app-name {\r\n font-weight: 500;\r\n color: var(--primary-color);\r\n }\r\n\r\n .read-btn {\r\n background: none;\r\n border: none;\r\n color: var(--text-muted);\r\n cursor: pointer;\r\n font-size: 14px;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .read-btn:hover {\r\n color: var(--success-color);\r\n }\r\n\r\n .delete-btn {\r\n background: none;\r\n border: none;\r\n color: var(--text-muted);\r\n cursor: pointer;\r\n font-size: 14px;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .delete-btn:hover {\r\n color: var(--error-color);\r\n }\r\n\r\n .empty-state {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 100%;\r\n color: var(--text-muted);\r\n font-size: 14px;\r\n }\r\n\r\n .panel-footer {\r\n padding: 12px 16px;\r\n border-top: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .footer-actions {\r\n display: flex;\r\n gap: 8px;\r\n }\r\n\r\n .footer-actions .action-btn {\r\n flex: 1;\r\n }\r\n\r\n .action-btn {\r\n width: 100%;\r\n padding: 8px;\r\n background-color: var(--primary-color);\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-weight: 500;\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .action-btn:hover {\r\n background-color: var(--primary-hover);\r\n }\r\n\r\n .delete-all-btn {\r\n background-color: var(--error-color);\r\n color: white;\r\n }\r\n\r\n .delete-all-btn:hover {\r\n background-color: #d32f2f; /* Darker red for hover */\r\n }\r\n\r\n @media (max-width: 600px) {\r\n .notification-panel {\r\n width: 100%;\r\n right: -100%;\r\n }\r\n }\r\n `]\r\n})\r\nexport class NotificationPanelComponent implements OnInit, OnDestroy {\r\n @Output() notificationRead = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n isOpen = false;\r\n notifications: NotificationDto[] = [];\r\n currentTheme: Theme = 'light';\r\n activeTab: 'unread' | 'read' = 'unread'; // Default to unread tab\r\n private destroy$ = new Subject<void>();\r\n\r\n get unreadNotifications(): NotificationDto[] {\r\n return this.notifications.filter(n => !n.isRead);\r\n }\r\n\r\n get readNotifications(): NotificationDto[] {\r\n return this.notifications.filter(n => n.isRead);\r\n }\r\n\r\n get currentNotifications(): NotificationDto[] {\r\n return this.activeTab === 'unread' ? this.unreadNotifications : this.readNotifications;\r\n }\r\n\r\n getNotificationMessage(notification: NotificationDto): string {\r\n return notification.messageHtml || notification.message || '';\r\n }\r\n\r\n constructor(private authService: MesAuthService, private toastService: ToastService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadNotifications();\r\n\r\n // Listen for new real-time notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((notification: RealTimeNotificationDto) => {\r\n // Show toast for new notification\r\n this.toastService.show(\r\n notification.messageHtml || notification.message || '',\r\n notification.title,\r\n 'info',\r\n 5000\r\n );\r\n // Reload notifications list\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n private loadNotifications() {\r\n this.authService.getNotifications(1, 50, true).subscribe({ // includeRead = true to get both read and unread\r\n next: (response: PagedList<NotificationDto>) => {\r\n this.notifications = response.items || [];\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n open() {\r\n this.isOpen = true;\r\n this.activeTab = 'unread'; // Reset to unread tab when opening\r\n }\r\n\r\n close() {\r\n this.isOpen = false;\r\n }\r\n\r\n switchTab(tab: 'unread' | 'read') {\r\n this.activeTab = tab;\r\n }\r\n\r\n markAsRead(notificationId: string, event?: Event) {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n this.authService.markAsRead(notificationId).subscribe({\r\n next: () => {\r\n const notification = this.notifications.find(n => n.id === notificationId);\r\n if (notification) {\r\n notification.isRead = true;\r\n this.notificationRead.emit();\r\n }\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n markAllAsRead() {\r\n this.authService.markAllAsRead().subscribe({\r\n next: () => {\r\n this.notifications.forEach(n => n.isRead = true);\r\n this.notificationRead.emit();\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n deleteAllRead() {\r\n const readNotificationIds = this.notifications\r\n .filter(n => n.isRead)\r\n .map(n => n.id);\r\n\r\n // Delete all read notifications\r\n const deletePromises = readNotificationIds.map(id =>\r\n this.authService.deleteNotification(id).toPromise()\r\n );\r\n\r\n Promise.all(deletePromises).then(() => {\r\n // Remove all read notifications from the local array\r\n this.notifications = this.notifications.filter(n => !n.isRead);\r\n }).catch((err) => {\r\n // If bulk delete fails, reload notifications to get current state\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n deleteAllUnread() {\r\n const unreadNotificationIds = this.notifications\r\n .filter(n => !n.isRead)\r\n .map(n => n.id);\r\n\r\n // Delete all unread notifications\r\n const deletePromises = unreadNotificationIds.map(id =>\r\n this.authService.deleteNotification(id).toPromise()\r\n );\r\n\r\n Promise.all(deletePromises).then(() => {\r\n // Remove all unread notifications from the local array\r\n this.notifications = this.notifications.filter(n => n.isRead);\r\n }).catch((err) => {\r\n // If bulk delete fails, reload notifications to get current state\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n delete(notificationId: string, event: Event) {\r\n event.stopPropagation();\r\n this.authService.deleteNotification(notificationId).subscribe({\r\n next: () => {\r\n this.notifications = this.notifications.filter(n => n.id !== notificationId);\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n formatDate(dateString: string): string {\r\n const date = new Date(dateString);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return 'Now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n \r\n return date.toLocaleDateString();\r\n }\r\n}\r\n","import { Component, ViewChild, AfterViewInit } from '@angular/core';\r\nimport { ToastContainerComponent } from './toast-container.component';\r\nimport { UserProfileComponent } from './user-profile.component';\r\nimport { NotificationPanelComponent } from './notification-panel.component';\r\n\r\n@Component({\r\n selector: 'ma-user',\r\n standalone: true,\r\n imports: [ToastContainerComponent, UserProfileComponent, NotificationPanelComponent],\r\n template: `\r\n <ma-toast-container></ma-toast-container>\r\n <div class=\"user-header\">\r\n <ma-user-profile (notificationClick)=\"notificationPanel.open()\"></ma-user-profile>\r\n </div>\r\n <ma-notification-panel #notificationPanel (notificationRead)=\"onNotificationRead()\"></ma-notification-panel>\r\n `,\r\n styles: [`\r\n .user-header {\r\n display: flex;\r\n justify-content: flex-end;\r\n }\r\n `]\r\n})\r\nexport class MaUserComponent implements AfterViewInit {\r\n @ViewChild(UserProfileComponent) userProfile?: UserProfileComponent;\r\n\r\n ngAfterViewInit() {\r\n // Ensure proper initialization\r\n if (this.userProfile) {\r\n this.userProfile.loadUnreadCount();\r\n }\r\n }\r\n\r\n onNotificationRead() {\r\n if (this.userProfile) {\r\n this.userProfile.loadUnreadCount();\r\n }\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, Output, EventEmitter, HostBinding } from '@angular/core';\r\nimport { NgIf } from '@angular/common';\r\nimport { MesAuthService } from './mes-auth.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-notification-badge',\r\n standalone: true,\r\n imports: [NgIf],\r\n template: `\r\n <button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"unreadCount > 0\">{{ unreadCount }}</span>\r\n </button>\r\n `,\r\n styles: [`\r\n :host {\r\n --error-color: #f44336;\r\n }\r\n\r\n :host(.theme-dark) {\r\n --error-color: #ef5350;\r\n }\r\n\r\n .notification-btn {\r\n position: relative;\r\n background: none;\r\n border: none;\r\n font-size: 24px;\r\n cursor: pointer;\r\n padding: 8px;\r\n transition: opacity 0.2s;\r\n }\r\n\r\n .notification-btn:hover {\r\n opacity: 0.7;\r\n }\r\n\r\n .icon {\r\n display: inline-block;\r\n }\r\n\r\n .badge {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n background-color: var(--error-color);\r\n color: white;\r\n border-radius: 50%;\r\n width: 20px;\r\n height: 20px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n font-weight: bold;\r\n }\r\n `]\r\n})\r\nexport class NotificationBadgeComponent implements OnInit, OnDestroy {\r\n @Output() notificationClick = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n \r\n unreadCount = 0;\r\n currentTheme: Theme = 'light';\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private authService: MesAuthService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadUnreadCount();\r\n \r\n // Listen for new notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(() => {\r\n this.loadUnreadCount();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n private loadUnreadCount() {\r\n this.authService.getUnreadCount().subscribe({\r\n next: (response: any) => {\r\n this.unreadCount = response.unreadCount || 0;\r\n },\r\n error: (err) => console.error('Error loading unread count:', err)\r\n });\r\n }\r\n\r\n onNotificationClick() {\r\n this.notificationClick.emit();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.MesAuthService","i3.ThemeService","i1.ToastService","i2.ThemeService","i2.ToastService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mesauth-angular.mjs","sources":["../../src/mes-auth.service.ts","../../src/mes-auth.interceptor.ts","../../src/mes-auth.module.ts","../../src/theme.service.ts","../../src/user-profile.component.ts","../../src/toast.service.ts","../../src/toast-container.component.ts","../../src/notification-panel.component.ts","../../src/ma-user.component.ts","../../src/notification-badge.component.ts","../../src/mesauth-angular.ts"],"sourcesContent":["import { inject, Injectable } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { HubConnection, HubConnectionBuilder, LogLevel } from '@microsoft/signalr';\r\nimport { BehaviorSubject, Subject, Observable } from 'rxjs';\r\nimport { tap, filter, debounceTime } from 'rxjs/operators';\r\nimport { Router, NavigationEnd } from '@angular/router';\r\n\r\nexport interface MesAuthConfig { \r\n apiBaseUrl: string;\r\n withCredentials?: boolean;\r\n userBaseUrl?: string;\r\n}\r\n\r\nexport interface IUser {\r\n userId?: string;\r\n userName?: string;\r\n fullName?: string;\r\n gender?: string;\r\n email?: string;\r\n phoneNumber?: string;\r\n department?: string;\r\n position?: string;\r\n tokenVersion?: string;\r\n permEndpoint?: string;\r\n perms?: Set<string>;\r\n employeeCode?: string;\r\n hrFullNameVn?: string;\r\n hrFullNameEn?: string;\r\n hrPosition?: string;\r\n hrJobTitle?: string;\r\n hrGender?: string;\r\n hrMobile?: string;\r\n hrEmail?: string;\r\n hrJoinDate?: string;\r\n hrBirthDate?: string;\r\n hrWorkStatus?: string;\r\n hrDoiTuong?: string;\r\n hrTeamCode?: string;\r\n hrLineCode?: string;\r\n}\r\n\r\nexport enum NotificationType {\r\n Info = 'Info',\r\n Warning = 'Warning',\r\n Error = 'Error',\r\n Success = 'Success'\r\n}\r\n\r\nexport interface NotificationDto {\r\n id: string;\r\n title: string;\r\n message: string;\r\n messageHtml?: string;\r\n url?: string;\r\n type: NotificationType;\r\n isRead: boolean;\r\n createdAt: string;\r\n sourceAppName: string;\r\n sourceAppIconUrl?: string;\r\n}\r\n\r\nexport interface FrontEndRoute {\r\n id: number;\r\n roleId: string;\r\n roleName: string;\r\n routePath: string;\r\n routeName: string;\r\n description?: string;\r\n icon?: string;\r\n cssClass?: string;\r\n parentId?: number | null;\r\n sortOrder: number;\r\n isLabel: boolean;\r\n isActive: boolean;\r\n createdAt: string;\r\n updatedAt?: string;\r\n children: FrontEndRoute[];\r\n}\r\n\r\nexport interface UserFrontEndRoutesGrouped {\r\n appId: string;\r\n appName: string;\r\n feUrl?: string;\r\n routes: FrontEndRoute[];\r\n}\r\n\r\nexport interface FrontEndRouteMaster {\r\n id: number;\r\n appId: string;\r\n routePath: string;\r\n routeName: string;\r\n description?: string;\r\n icon?: string;\r\n cssClass?: string;\r\n parentId?: number | null;\r\n sortOrder: number;\r\n isLabel: boolean;\r\n isActive: boolean;\r\n createdAt: string;\r\n updatedAt?: string;\r\n}\r\n\r\nexport interface CreateFrontEndRouteDto {\r\n routePath: string;\r\n routeName: string;\r\n description?: string;\r\n icon?: string;\r\n cssClass?: string;\r\n parentId?: number | null;\r\n sortOrder?: number;\r\n isLabel?: boolean;\r\n}\r\n\r\nexport interface PagedList<T> {\r\n items: T[];\r\n totalCount: number;\r\n page: number;\r\n pageSize: number;\r\n totalPages: number;\r\n hasNext: boolean;\r\n hasPrevious: boolean;\r\n}\r\n\r\nexport interface RealTimeNotificationDto {\r\n id: string;\r\n title: string;\r\n message: string;\r\n messageHtml?: string;\r\n url?: string;\r\n type: NotificationType;\r\n createdAt: string;\r\n sourceAppName: string;\r\n sourceAppIconUrl?: string;\r\n}\r\n\r\n@Injectable()\r\nexport class MesAuthService {\r\n private hubConnection: HubConnection | null = null;\r\n private _currentUser = new BehaviorSubject<IUser | null>(null);\r\n public currentUser$: Observable<IUser | null> = this._currentUser.asObservable();\r\n private _notifications = new Subject<any>();\r\n public notifications$: Observable<any> = this._notifications.asObservable();\r\n\r\n private apiBase = '';\r\n private config: MesAuthConfig | null = null;\r\n private http!: HttpClient;\r\n private router?: Router;\r\n\r\n constructor() {\r\n // Empty constructor - all dependencies passed to init()\r\n }\r\n\r\n private isProtectedRoute(url: string): boolean {\r\n // Consider routes protected if they don't include auth-related paths\r\n return !url.includes('/login') && !url.includes('/auth') && !url.includes('/signin') && !url.includes('/logout');\r\n }\r\n\r\n init(config: MesAuthConfig, httpClient: HttpClient, router?: Router) {\r\n this.config = config;\r\n this.http = httpClient;\r\n this.router = router;\r\n this.apiBase = config.apiBaseUrl.replace(/\\/$/, '');\r\n\r\n // Listen for route changes - only refresh user data if needed for SPA navigation\r\n // This helps maintain authentication state in single-page applications\r\n if (this.router) {\r\n this.router.events\r\n .pipe(\r\n filter(event => event instanceof NavigationEnd),\r\n debounceTime(1000) // Longer debounce to avoid interfering with login flow\r\n )\r\n .subscribe((event: NavigationEnd) => {\r\n // Only refresh if user is logged in and navigating to protected routes\r\n // Avoid refreshing during login/logout flows\r\n if (this._currentUser.value && this.isProtectedRoute(event.url)) {\r\n // Small delay to ensure any login/logout operations complete\r\n setTimeout(() => {\r\n if (this._currentUser.value) {\r\n this.refreshUser();\r\n }\r\n }, 100);\r\n }\r\n });\r\n }\r\n\r\n this.fetchCurrentUser();\r\n this.fetchInitialNotifications();\r\n }\r\n\r\n getConfig(): MesAuthConfig | null {\r\n return this.config;\r\n }\r\n\r\n private fetchCurrentUser() {\r\n if (!this.apiBase) return;\r\n const url = `${this.apiBase}/auth/me`;\r\n this.http.get(url, { withCredentials: this.config?.withCredentials ?? true }).subscribe({\r\n next: (u) => {\r\n this._currentUser.next(u);\r\n if (u && this.config) {\r\n this.startConnection(this.config);\r\n }\r\n },\r\n error: (err) => {\r\n // Silently handle auth errors (401/403) - user is not logged in\r\n if (err.status === 401 || err.status === 403) {\r\n this._currentUser.next(null);\r\n }\r\n }\r\n });\r\n }\r\n\r\n private fetchInitialNotifications() {\r\n if (!this.apiBase) return;\r\n this.http.get(`${this.apiBase}/notif/me`, { withCredentials: this.config?.withCredentials ?? true }).subscribe({\r\n next: (notifications: any) => {\r\n if (Array.isArray(notifications?.items)) {\r\n notifications.items.forEach((n: any) => this._notifications.next(n));\r\n }\r\n },\r\n error: (err) => {\r\n // Silently handle auth errors (401/403) - user is not logged in\r\n // No need to emit anything\r\n }\r\n });\r\n }\r\n\r\n public getUnreadCount(): Observable<any> {\r\n return this.http.get(`${this.apiBase}/notif/me/unread-count`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public getNotifications(page: number = 1, pageSize: number = 20, includeRead: boolean = false, type?: string): Observable<any> {\r\n let url = `${this.apiBase}/notif/me?page=${page}&pageSize=${pageSize}&includeRead=${includeRead}`;\r\n if (type) {\r\n url += `&type=${type}`;\r\n }\r\n return this.http.get(url, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public markAsRead(notificationId: string): Observable<any> {\r\n return this.http.patch(`${this.apiBase}/notif/${notificationId}/read`, {}, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public markAllAsRead(): Observable<any> {\r\n return this.http.patch(`${this.apiBase}/notif/me/read-all`, {}, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n public deleteNotification(notificationId: string): Observable<any> {\r\n return this.http.delete(`${this.apiBase}/notif/${notificationId}`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n /**\r\n * Get frontend routes assigned to the current user\r\n * Returns routes grouped by application\r\n */\r\n public getFrontEndRoutes(): Observable<UserFrontEndRoutesGrouped[]> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.get<UserFrontEndRoutesGrouped[]>(`${this.apiBase}/fe-routes/me`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n /**\r\n * Get master routes for a specific application\r\n * @param appId - The application ID\r\n */\r\n public getRouteMasters(appId: string): Observable<FrontEndRouteMaster[]> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.get<FrontEndRouteMaster[]>(`${this.apiBase}/fe-routes/masters/${appId}`, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n /**\r\n * Register/sync frontend routes for an application\r\n * This is typically called on app startup to sync routes from the frontend app\r\n * @param appId - The application ID (passed via X-App-Id header)\r\n * @param routes - Array of route definitions\r\n */\r\n public registerFrontEndRoutes(appId: string, routes: CreateFrontEndRouteDto[]): Observable<any> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n const headers = { 'X-App-Id': appId };\r\n return this.http.post(`${this.apiBase}/fe-routes/register`, routes, {\r\n headers,\r\n withCredentials: this.config?.withCredentials ?? true\r\n });\r\n }\r\n\r\n /**\r\n * Create a new route master\r\n * @param appId - The application ID\r\n * @param route - Route details\r\n */\r\n public createRouteMaster(appId: string, route: CreateFrontEndRouteDto): Observable<FrontEndRouteMaster> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.post<FrontEndRouteMaster>(`${this.apiBase}/fe-routes/masters`, {\r\n appId,\r\n ...route\r\n }, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n /**\r\n * Update an existing route master\r\n * @param routeId - The route master ID\r\n * @param route - Updated route details\r\n */\r\n public updateRouteMaster(routeId: number, route: Partial<CreateFrontEndRouteDto> & { isActive?: boolean }): Observable<FrontEndRouteMaster> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.put<FrontEndRouteMaster>(`${this.apiBase}/fe-routes/masters/${routeId}`, route, {\r\n withCredentials: this.config?.withCredentials ?? true\r\n });\r\n }\r\n\r\n /**\r\n * Delete a route master\r\n * @param routeId - The route master ID\r\n */\r\n public deleteRouteMaster(routeId: number): Observable<any> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.delete(`${this.apiBase}/fe-routes/masters/${routeId}`, {\r\n withCredentials: this.config?.withCredentials ?? true\r\n });\r\n }\r\n\r\n /**\r\n * Assign a route to a role\r\n * @param routeMasterId - The route master ID\r\n * @param roleId - The role ID (GUID)\r\n */\r\n public assignRouteToRole(routeMasterId: number, roleId: string): Observable<any> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.post(`${this.apiBase}/fe-routes/mappings`, {\r\n routeMasterId,\r\n roleId\r\n }, { withCredentials: this.config?.withCredentials ?? true });\r\n }\r\n\r\n /**\r\n * Remove a route assignment from a role\r\n * @param mappingId - The mapping ID\r\n */\r\n public removeRouteFromRole(mappingId: number): Observable<any> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.delete(`${this.apiBase}/fe-routes/mappings/${mappingId}`, {\r\n withCredentials: this.config?.withCredentials ?? true\r\n });\r\n }\r\n\r\n /**\r\n * Get route-to-role mappings for a specific role\r\n * @param roleId - The role ID (GUID)\r\n */\r\n public getRouteMappingsByRole(roleId: string): Observable<any[]> {\r\n if (!this.apiBase) throw new Error('MesAuth not initialized');\r\n return this.http.get<any[]>(`${this.apiBase}/fe-routes/mappings?roleId=${roleId}`, {\r\n withCredentials: this.config?.withCredentials ?? true\r\n });\r\n }\r\n\r\n private startConnection(config: MesAuthConfig) {\r\n if (this.hubConnection) return;\r\n const signalrUrl = config.apiBaseUrl.replace(/\\/$/, '') + '/hub/notification';\r\n const builder = new HubConnectionBuilder()\r\n .withUrl(signalrUrl, { withCredentials: config.withCredentials ?? true })\r\n .withAutomaticReconnect()\r\n .configureLogging(LogLevel.Warning);\r\n\r\n this.hubConnection = builder.build();\r\n\r\n this.hubConnection.on('ReceiveNotification', (n: any) => {\r\n this._notifications.next(n);\r\n });\r\n\r\n this.hubConnection.start().then(() => {}).catch((err) => {});\r\n\r\n this.hubConnection.onclose(() => {});\r\n this.hubConnection.onreconnecting(() => {});\r\n this.hubConnection.onreconnected(() => {});\r\n }\r\n\r\n public stop() {\r\n if (!this.hubConnection) return;\r\n this.hubConnection.stop().catch(() => {});\r\n this.hubConnection = null;\r\n }\r\n\r\n public logout(): Observable<any> {\r\n const url = `${this.apiBase}/auth/logout`;\r\n return this.http.post(url, {}, { withCredentials: this.config?.withCredentials ?? true }).pipe(\r\n tap(() => {\r\n this._currentUser.next(null);\r\n this.stop();\r\n })\r\n );\r\n }\r\n\r\n public refreshUser() {\r\n this.fetchCurrentUser();\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';\r\nimport { Observable, throwError } from 'rxjs';\r\nimport { catchError } from 'rxjs/operators';\r\nimport { Router } from '@angular/router';\r\nimport { MesAuthService } from './mes-auth.service';\r\n\r\n@Injectable()\r\nexport class MesAuthInterceptor implements HttpInterceptor {\r\n constructor(private authService: MesAuthService, private router: Router) {}\r\n\r\n intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n return next.handle(req).pipe(\r\n catchError((error: HttpErrorResponse) => {\r\n if (error.status === 403) {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n\r\n // Use router URL for internal navigation (cleaner URLs)\r\n // Falls back to window.location for full URL if needed\r\n const currentUrl = this.router.url || window.location.pathname + window.location.search;\r\n const returnUrl = encodeURIComponent(currentUrl);\r\n\r\n window.location.href = `${baseUrl}/403?returnUrl=${returnUrl}`;\r\n }\r\n return throwError(error);\r\n })\r\n );\r\n }\r\n}\r\n","import { NgModule } from '@angular/core';\r\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\r\nimport { MesAuthService } from './mes-auth.service';\r\nimport { MesAuthInterceptor } from './mes-auth.interceptor';\r\n\r\n@NgModule({\r\n providers: [\r\n MesAuthService,\r\n { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }\r\n ]\r\n})\r\nexport class MesAuthModule {}\r\n","import { Injectable, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\n\r\nexport type Theme = 'light' | 'dark';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class ThemeService implements OnDestroy {\r\n private _currentTheme = new BehaviorSubject<Theme>('light');\r\n public currentTheme$: Observable<Theme> = this._currentTheme.asObservable();\r\n private observer: MutationObserver | null = null;\r\n\r\n constructor() {\r\n this.detectTheme();\r\n this.startWatching();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.stopWatching();\r\n }\r\n\r\n private detectTheme(): void {\r\n const html = document.documentElement;\r\n const isDark = html.classList.contains('dark') ||\r\n html.getAttribute('data-theme') === 'dark' ||\r\n html.getAttribute('theme') === 'dark' ||\r\n html.getAttribute('data-coreui-theme') === 'dark';\r\n\r\n this._currentTheme.next(isDark ? 'dark' : 'light');\r\n }\r\n\r\n private startWatching(): void {\r\n if (typeof MutationObserver === 'undefined') {\r\n // Fallback for older browsers - check periodically\r\n setInterval(() => this.detectTheme(), 1000);\r\n return;\r\n }\r\n\r\n this.observer = new MutationObserver(() => {\r\n this.detectTheme();\r\n });\r\n\r\n this.observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class', 'data-theme', 'theme', 'data-coreui-theme']\r\n });\r\n }\r\n\r\n private stopWatching(): void {\r\n if (this.observer) {\r\n this.observer.disconnect();\r\n this.observer = null;\r\n }\r\n }\r\n\r\n get currentTheme(): Theme {\r\n return this._currentTheme.value;\r\n }\r\n\r\n // Method to manually set theme if needed\r\n setTheme(theme: Theme): void {\r\n this._currentTheme.next(theme);\r\n }\r\n\r\n // Re-detect theme from DOM\r\n refreshTheme(): void {\r\n this.detectTheme();\r\n }\r\n}","import { Component, OnInit, OnDestroy, Output, EventEmitter, HostBinding, HostListener } from '@angular/core';\r\nimport { NgIf } from '@angular/common';\r\nimport { Router } from '@angular/router';\r\nimport { MesAuthService, IUser } from './mes-auth.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-user-profile',\r\n standalone: true,\r\n imports: [NgIf],\r\n template: `\r\n <div class=\"user-profile-container\">\r\n <!-- Not logged in -->\r\n <ng-container *ngIf=\"!currentUser\">\r\n <button class=\"login-btn\" (click)=\"onLogin()\">\r\n Login\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Logged in -->\r\n <ng-container *ngIf=\"currentUser\">\r\n <div class=\"user-header\">\r\n <button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"unreadCount > 0\">{{ unreadCount }}</span>\r\n </button>\r\n\r\n <div class=\"user-menu-wrapper\">\r\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\">\r\n <img \r\n *ngIf=\"currentUser.fullName || currentUser.userName\"\r\n [src]=\"getAvatarUrl(currentUser)\" \r\n [alt]=\"currentUser.fullName || currentUser.userName\"\r\n class=\"avatar\"\r\n />\r\n <span *ngIf=\"!(currentUser.fullName || currentUser.userName)\" class=\"avatar-initial\">\r\n {{ getLastNameInitial(currentUser) }}\r\n </span>\r\n </button>\r\n\r\n <div class=\"mes-dropdown-menu\" *ngIf=\"dropdownOpen\">\r\n <div class=\"mes-dropdown-header\">\r\n {{ currentUser.fullName || currentUser.userName }}\r\n </div>\r\n <button class=\"mes-dropdown-item profile-link\" (click)=\"onViewProfile()\">\r\n View Profile\r\n </button>\r\n <button class=\"mes-dropdown-item logout-item\" (click)=\"onLogout()\">\r\n Logout\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --primary-color: #1976d2;\r\n --primary-hover: #1565c0;\r\n --primary-light: rgba(25, 118, 210, 0.1);\r\n --error-color: #f44336;\r\n --error-light: #ffebee;\r\n --text-primary: #333;\r\n --text-secondary: #666;\r\n --text-muted: #999;\r\n --bg-primary: white;\r\n --bg-secondary: #f5f5f5;\r\n --bg-tertiary: #fafafa;\r\n --bg-hover: #f5f5f5;\r\n --border-color: #e0e0e0;\r\n --border-light: #f0f0f0;\r\n --shadow: rgba(0, 0, 0, 0.15);\r\n --shadow-light: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --primary-color: #90caf9;\r\n --primary-hover: #64b5f6;\r\n --primary-light: rgba(144, 202, 249, 0.1);\r\n --error-color: #ef5350;\r\n --error-light: rgba(239, 83, 80, 0.1);\r\n --text-primary: #e0e0e0;\r\n --text-secondary: #b0b0b0;\r\n --text-muted: #888;\r\n --bg-primary: #1e1e1e;\r\n --bg-secondary: #2d2d2d;\r\n --bg-tertiary: #252525;\r\n --bg-hover: #333;\r\n --border-color: #404040;\r\n --border-light: #333;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n --shadow-light: rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n .user-profile-container {\r\n display: flex;\r\n align-items: center;\r\n gap: 16px;\r\n padding: 0 16px;\r\n }\r\n\r\n .login-btn {\r\n padding: 8px 16px;\r\n background-color: var(--primary-color);\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-weight: 500;\r\n transition: background-color 0.3s;\r\n }\r\n\r\n .login-btn:hover {\r\n background-color: var(--primary-hover);\r\n }\r\n\r\n .user-header {\r\n display: flex;\r\n align-items: center;\r\n gap: 16px;\r\n }\r\n\r\n .notification-btn {\r\n position: relative;\r\n background: none;\r\n border: none;\r\n font-size: 24px;\r\n cursor: pointer;\r\n padding: 8px;\r\n transition: opacity 0.2s;\r\n }\r\n\r\n .notification-btn:hover {\r\n opacity: 0.7;\r\n }\r\n\r\n .icon {\r\n display: inline-block;\r\n }\r\n\r\n .badge {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n background-color: var(--error-color);\r\n color: white;\r\n border-radius: 50%;\r\n width: 20px;\r\n height: 20px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n font-weight: bold;\r\n }\r\n\r\n .user-menu-wrapper {\r\n position: relative;\r\n }\r\n\r\n .user-menu-btn {\r\n background: none;\r\n border: none;\r\n cursor: pointer;\r\n padding: 4px;\r\n border-radius: 50%;\r\n transition: background-color 0.2s;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n\r\n .user-menu-btn:hover {\r\n background-color: var(--primary-light);\r\n }\r\n\r\n .avatar {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 50%;\r\n object-fit: cover;\r\n background-color: #e0e0e0;\r\n }\r\n\r\n .avatar-initial {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 50%;\r\n background-color: var(--primary-color);\r\n color: white;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-weight: bold;\r\n font-size: 16px;\r\n }\r\n\r\n .mes-dropdown-menu {\r\n position: absolute;\r\n top: calc(100% + 8px);\r\n right: 0;\r\n background: var(--bg-primary);\r\n border: 1px solid var(--border-color);\r\n border-radius: 4px;\r\n box-shadow: 0 2px 8px var(--shadow);\r\n min-width: 200px;\r\n z-index: 1000;\r\n overflow: hidden;\r\n }\r\n\r\n .mes-dropdown-header {\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--border-light);\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n font-size: 14px;\r\n }\r\n\r\n .mes-dropdown-item {\r\n display: block;\r\n width: 100%;\r\n padding: 12px 16px;\r\n border: none;\r\n background: none;\r\n text-align: left;\r\n cursor: pointer;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n text-decoration: none;\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .mes-dropdown-item:hover {\r\n background-color: var(--bg-hover);\r\n }\r\n\r\n .profile-link {\r\n color: var(--primary-color);\r\n }\r\n\r\n .logout-item {\r\n border-top: 1px solid var(--border-light);\r\n color: var(--error-color);\r\n }\r\n\r\n .logout-item:hover {\r\n background-color: var(--error-light);\r\n }\r\n\r\n .user-info {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n .user-name {\r\n font-weight: 500;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n }\r\n\r\n .user-position {\r\n font-size: 12px;\r\n color: var(--text-secondary);\r\n }\r\n\r\n .logout-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n padding: 4px 8px;\r\n transition: color 0.2s;\r\n }\r\n\r\n .logout-btn:hover {\r\n color: var(--primary-color);\r\n }\r\n\r\n @media (max-width: 768px) {\r\n .user-info {\r\n display: none;\r\n }\r\n\r\n .avatar {\r\n width: 32px;\r\n height: 32px;\r\n }\r\n }\r\n `]\r\n})\r\nexport class UserProfileComponent implements OnInit, OnDestroy {\r\n @Output() notificationClick = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n currentUser: IUser | null = null;\r\n currentTheme: Theme = 'light';\r\n unreadCount = 0;\r\n dropdownOpen = false;\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private authService: MesAuthService, private router: Router, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.authService.currentUser$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(user => {\r\n this.currentUser = user;\r\n });\r\n\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadUnreadCount();\r\n\r\n // Listen for new notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(() => {\r\n console.log('Notification received, updating unread count');\r\n this.loadUnreadCount();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n loadUnreadCount() {\r\n this.authService.getUnreadCount().subscribe({\r\n next: (response: any) => {\r\n this.unreadCount = response.unreadCount || 0;\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n getAvatarUrl(user: IUser): string {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.apiBaseUrl || '';\r\n \r\n // Use userId for the avatar endpoint\r\n const userId = user.userId;\r\n if (userId && baseUrl) {\r\n return `${baseUrl.replace(/\\/$/, '')}/auth/${userId}/avatar`;\r\n }\r\n \r\n // Fallback to UI avatars service if no userId or baseUrl\r\n const displayName = user.userName || user.userId || 'User';\r\n return `https://ui-avatars.com/api/?name=${encodeURIComponent(displayName)}&background=1976d2&color=fff`;\r\n }\r\n\r\n getLastNameInitial(user: IUser): string {\r\n const fullName = user.fullName || user.userName || 'U';\r\n const parts = fullName.split(' ');\r\n const lastPart = parts[parts.length - 1];\r\n return lastPart.charAt(0).toUpperCase();\r\n }\r\n\r\n toggleDropdown() {\r\n this.dropdownOpen = !this.dropdownOpen;\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: Event) {\r\n const target = event.target as HTMLElement;\r\n const clickedInside = target.closest('.user-menu-wrapper');\r\n if (!clickedInside) {\r\n this.dropdownOpen = false;\r\n }\r\n }\r\n\r\n onLogin() {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n const returnUrl = encodeURIComponent(this.router.url);\r\n window.location.href = `${baseUrl}/login?returnUrl=${returnUrl}`;\r\n }\r\n\r\n onViewProfile() {\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n window.location.href = `${baseUrl}/profile`;\r\n this.dropdownOpen = false;\r\n }\r\n\r\n onLogout() {\r\n this.authService.logout().subscribe({\r\n next: () => {\r\n // Clear current user after successful logout\r\n this.dropdownOpen = false;\r\n \r\n // Navigate to login with return URL\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n const returnUrl = encodeURIComponent(window.location.href);\r\n window.location.href = `${baseUrl}/login?returnUrl=${returnUrl}`;\r\n },\r\n error: (err) => {\r\n // Still navigate to login even if logout fails\r\n const config = this.authService.getConfig();\r\n const baseUrl = config?.userBaseUrl || '';\r\n window.location.href = `${baseUrl}/login`;\r\n }\r\n });\r\n }\r\n\r\n onNotificationClick() {\r\n this.notificationClick.emit();\r\n }\r\n}\r\n\r\n","import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\n\r\nexport interface Toast {\r\n id: string;\r\n message: string;\r\n title?: string;\r\n type: 'info' | 'success' | 'warning' | 'error';\r\n duration?: number;\r\n}\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class ToastService {\r\n private toasts$ = new BehaviorSubject<Toast[]>([]);\r\n public toasts: Observable<Toast[]> = this.toasts$.asObservable();\r\n\r\n show(message: string, title?: string, type: 'info' | 'success' | 'warning' | 'error' = 'info', duration: number = 5000) {\r\n const id = Math.random().toString(36).substr(2, 9);\r\n const toast: Toast = {\r\n id,\r\n message,\r\n title,\r\n type,\r\n duration\r\n };\r\n\r\n const currentToasts = this.toasts$.value;\r\n this.toasts$.next([...currentToasts, toast]);\r\n\r\n if (duration > 0) {\r\n setTimeout(() => {\r\n this.remove(id);\r\n }, duration);\r\n }\r\n\r\n return id;\r\n }\r\n\r\n remove(id: string) {\r\n const currentToasts = this.toasts$.value;\r\n this.toasts$.next(currentToasts.filter(t => t.id !== id));\r\n }\r\n\r\n clear() {\r\n this.toasts$.next([]);\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, HostBinding } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { ToastService, Toast } from './toast.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-toast-container',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"toast-container\">\r\n <div \r\n *ngFor=\"let toast of toasts\"\r\n class=\"toast\"\r\n [class]=\"'toast-' + toast.type\"\r\n [@slideIn]\r\n >\r\n <div class=\"toast-content\">\r\n <div *ngIf=\"toast.title\" class=\"toast-title\">{{ toast.title }}</div>\r\n <div class=\"toast-message\" [innerHTML]=\"toast.message\"></div>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"close(toast.id)\" aria-label=\"Close\">\r\n ✕\r\n </button>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --info-color: #2196f3;\r\n --success-color: #4caf50;\r\n --warning-color: #ff9800;\r\n --error-color: #f44336;\r\n --text-primary: #333;\r\n --bg-primary: white;\r\n --shadow: rgba(0, 0, 0, 0.15);\r\n --text-secondary: #999;\r\n --border-color: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --info-color: #64b5f6;\r\n --success-color: #81c784;\r\n --warning-color: #ffb74d;\r\n --error-color: #ef5350;\r\n --text-primary: #e0e0e0;\r\n --bg-primary: #1e1e1e;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n --text-secondary: #888;\r\n --border-color: rgba(255, 255, 255, 0.1);\r\n }\r\n\r\n .toast-container {\r\n position: fixed;\r\n top: 20px;\r\n right: 20px;\r\n z-index: 9999;\r\n pointer-events: none;\r\n }\r\n\r\n .toast {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 12px;\r\n padding: 12px 16px;\r\n margin-bottom: 12px;\r\n border-radius: 4px;\r\n background: var(--bg-primary);\r\n border: 1px solid var(--border-color);\r\n box-shadow: 0 4px 12px var(--shadow);\r\n pointer-events: auto;\r\n min-width: 280px;\r\n max-width: 400px;\r\n animation: slideIn 0.3s ease-out;\r\n }\r\n\r\n .toast-content {\r\n flex: 1;\r\n }\r\n\r\n .toast-title {\r\n font-weight: 600;\r\n font-size: 14px;\r\n margin-bottom: 4px;\r\n }\r\n\r\n .toast-message {\r\n font-size: 13px;\r\n line-height: 1.4;\r\n }\r\n\r\n .toast-close {\r\n background: none;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 18px;\r\n color: var(--text-secondary);\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .toast-close:hover {\r\n color: var(--text-primary);\r\n }\r\n\r\n /* Toast types */\r\n .toast-info {\r\n border-left: 4px solid var(--info-color);\r\n }\r\n\r\n .toast-info .toast-title {\r\n color: var(--info-color);\r\n }\r\n\r\n .toast-info .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-success {\r\n border-left: 4px solid var(--success-color);\r\n }\r\n\r\n .toast-success .toast-title {\r\n color: var(--success-color);\r\n }\r\n\r\n .toast-success .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-warning {\r\n border-left: 4px solid var(--warning-color);\r\n }\r\n\r\n .toast-warning .toast-title {\r\n color: var(--warning-color);\r\n }\r\n\r\n .toast-warning .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n .toast-error {\r\n border-left: 4px solid var(--error-color);\r\n }\r\n\r\n .toast-error .toast-title {\r\n color: var(--error-color);\r\n }\r\n\r\n .toast-error .toast-message {\r\n color: var(--text-primary);\r\n }\r\n\r\n @keyframes slideIn {\r\n from {\r\n transform: translateX(400px);\r\n opacity: 0;\r\n }\r\n to {\r\n transform: translateX(0);\r\n opacity: 1;\r\n }\r\n }\r\n\r\n @media (max-width: 600px) {\r\n .toast-container {\r\n top: 10px;\r\n right: 10px;\r\n left: 10px;\r\n }\r\n\r\n .toast {\r\n min-width: auto;\r\n max-width: 100%;\r\n }\r\n }\r\n `]\r\n})\r\nexport class ToastContainerComponent implements OnInit, OnDestroy {\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n toasts: Toast[] = [];\r\n currentTheme: Theme = 'light';\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private toastService: ToastService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.toastService.toasts\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(toasts => {\r\n this.toasts = toasts;\r\n });\r\n\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n close(id: string) {\r\n this.toastService.remove(id);\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, HostBinding, Output, EventEmitter } from '@angular/core';\r\nimport { NgIf, NgFor } from '@angular/common';\r\nimport { MesAuthService, NotificationDto, PagedList, RealTimeNotificationDto } from './mes-auth.service';\r\nimport { ToastService } from './toast.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-notification-panel',\r\n standalone: true,\r\n imports: [NgIf, NgFor],\r\n template: `\r\n <div class=\"notification-panel\" [class.open]=\"isOpen\">\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <h3>Notifications</h3>\r\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\">✕</button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button \r\n class=\"tab-btn\" \r\n [class.active]=\"activeTab === 'unread'\"\r\n (click)=\"switchTab('unread')\"\r\n >\r\n Unread ({{ unreadNotifications.length }})\r\n </button>\r\n <button \r\n class=\"tab-btn\" \r\n [class.active]=\"activeTab === 'read'\"\r\n (click)=\"switchTab('read')\"\r\n >\r\n Read ({{ readNotifications.length }})\r\n </button>\r\n </div>\r\n\r\n <!-- Notifications List -->\r\n <div class=\"notifications-list\">\r\n <ng-container *ngIf=\"currentNotifications.length > 0\">\r\n <div \r\n *ngFor=\"let notification of currentNotifications\"\r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.isRead\"\r\n (click)=\"markAsRead(notification.id)\"\r\n >\r\n <div class=\"notification-content\">\r\n <div class=\"notification-title\">{{ notification.title }}</div>\r\n <div class=\"notification-message\" [innerHTML]=\"getNotificationMessage(notification)\"></div>\r\n <div class=\"notification-meta\">\r\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\r\n <span class=\"time\">{{ formatDate(notification.createdAt) }}</span>\r\n </div>\r\n </div>\r\n <button \r\n class=\"read-btn\" \r\n (click)=\"markAsRead(notification.id, $event)\"\r\n title=\"Mark as read\"\r\n *ngIf=\"!notification.isRead\"\r\n >\r\n ✓\r\n </button>\r\n <button \r\n class=\"delete-btn\" \r\n (click)=\"delete(notification.id, $event)\"\r\n title=\"Delete notification\"\r\n *ngIf=\"notification.isRead\"\r\n >\r\n ✓\r\n </button>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"currentNotifications.length === 0\">\r\n <div class=\"empty-state\">\r\n No {{ activeTab }} notifications\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"panel-footer\" *ngIf=\"currentNotifications.length > 0\">\r\n <div class=\"footer-actions\" *ngIf=\"activeTab === 'unread'\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadNotifications.length > 0\">\r\n Mark all as read\r\n </button>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\" *ngIf=\"unreadNotifications.length > 0\">\r\n Delete all\r\n </button>\r\n </div>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\" *ngIf=\"activeTab === 'read' && readNotifications.length > 0\">\r\n Delete all\r\n </button>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n :host {\r\n --primary-color: #1976d2;\r\n --primary-hover: #1565c0;\r\n --success-color: #4caf50;\r\n --error-color: #f44336;\r\n --text-primary: #333;\r\n --text-secondary: #666;\r\n --text-muted: #999;\r\n --bg-primary: white;\r\n --bg-secondary: #f5f5f5;\r\n --bg-tertiary: #fafafa;\r\n --bg-hover: #f5f5f5;\r\n --bg-unread: #e3f2fd;\r\n --border-color: #e0e0e0;\r\n --border-light: #f0f0f0;\r\n --shadow: rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n :host(.theme-dark) {\r\n --primary-color: #90caf9;\r\n --primary-hover: #64b5f6;\r\n --success-color: #81c784;\r\n --error-color: #ef5350;\r\n --text-primary: #e0e0e0;\r\n --text-secondary: #b0b0b0;\r\n --text-muted: #888;\r\n --bg-primary: #1e1e1e;\r\n --bg-secondary: #2d2d2d;\r\n --bg-tertiary: #252525;\r\n --bg-hover: #333;\r\n --bg-unread: rgba(144, 202, 249, 0.1);\r\n --border-color: #404040;\r\n --border-light: #333;\r\n --shadow: rgba(0, 0, 0, 0.3);\r\n }\r\n\r\n .notification-panel {\r\n position: fixed;\r\n top: 0;\r\n right: -350px;\r\n width: 350px;\r\n height: 100vh;\r\n background: var(--bg-primary);\r\n box-shadow: -2px 0 8px var(--shadow);\r\n display: flex;\r\n flex-direction: column;\r\n z-index: 1000;\r\n transition: right 0.3s ease;\r\n }\r\n\r\n .notification-panel.open {\r\n right: 0;\r\n }\r\n\r\n .panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 16px;\r\n border-bottom: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .panel-header h3 {\r\n margin: 0;\r\n font-size: 18px;\r\n color: var(--text-primary);\r\n }\r\n\r\n .close-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary);\r\n padding: 0;\r\n width: 32px;\r\n height: 32px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: color 0.2s;\r\n }\r\n\r\n .close-btn:hover {\r\n color: var(--text-primary);\r\n }\r\n\r\n .tabs {\r\n display: flex;\r\n border-bottom: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .tab-btn {\r\n flex: 1;\r\n padding: 12px 16px;\r\n background: none;\r\n border: none;\r\n color: var(--text-secondary);\r\n cursor: pointer;\r\n font-size: 14px;\r\n font-weight: 500;\r\n transition: all 0.2s;\r\n border-bottom: 2px solid transparent;\r\n }\r\n\r\n .tab-btn:hover {\r\n background-color: var(--bg-hover);\r\n color: var(--text-primary);\r\n }\r\n\r\n .tab-btn.active {\r\n color: var(--primary-color);\r\n border-bottom-color: var(--primary-color);\r\n background-color: var(--bg-primary);\r\n }\r\n\r\n .notifications-list {\r\n flex: 1;\r\n overflow-y: auto;\r\n }\r\n\r\n .notification-item {\r\n display: flex;\r\n gap: 12px;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--border-light);\r\n cursor: pointer;\r\n background-color: var(--bg-tertiary);\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .notification-item:hover {\r\n background-color: var(--bg-hover);\r\n }\r\n\r\n .notification-item.unread {\r\n background-color: var(--bg-unread);\r\n }\r\n\r\n .notification-content {\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .notification-title {\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n font-size: 14px;\r\n margin-bottom: 4px;\r\n }\r\n\r\n .notification-message {\r\n color: var(--text-secondary);\r\n font-size: 13px;\r\n line-height: 1.4;\r\n margin-bottom: 6px;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 2;\r\n -webkit-box-orient: vertical;\r\n overflow: hidden;\r\n }\r\n\r\n .notification-meta {\r\n display: flex;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n color: var(--text-muted);\r\n }\r\n\r\n .app-name {\r\n font-weight: 500;\r\n color: var(--primary-color);\r\n }\r\n\r\n .read-btn {\r\n background: none;\r\n border: none;\r\n color: var(--text-muted);\r\n cursor: pointer;\r\n font-size: 14px;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .read-btn:hover {\r\n color: var(--success-color);\r\n }\r\n\r\n .delete-btn {\r\n background: none;\r\n border: none;\r\n color: var(--text-muted);\r\n cursor: pointer;\r\n font-size: 14px;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n transition: color 0.2s;\r\n }\r\n\r\n .delete-btn:hover {\r\n color: var(--error-color);\r\n }\r\n\r\n .empty-state {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n height: 100%;\r\n color: var(--text-muted);\r\n font-size: 14px;\r\n }\r\n\r\n .panel-footer {\r\n padding: 12px 16px;\r\n border-top: 1px solid var(--border-color);\r\n background-color: var(--bg-secondary);\r\n }\r\n\r\n .footer-actions {\r\n display: flex;\r\n gap: 8px;\r\n }\r\n\r\n .footer-actions .action-btn {\r\n flex: 1;\r\n }\r\n\r\n .action-btn {\r\n width: 100%;\r\n padding: 8px;\r\n background-color: var(--primary-color);\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font-weight: 500;\r\n transition: background-color 0.2s;\r\n }\r\n\r\n .action-btn:hover {\r\n background-color: var(--primary-hover);\r\n }\r\n\r\n .delete-all-btn {\r\n background-color: var(--error-color);\r\n color: white;\r\n }\r\n\r\n .delete-all-btn:hover {\r\n background-color: #d32f2f; /* Darker red for hover */\r\n }\r\n\r\n @media (max-width: 600px) {\r\n .notification-panel {\r\n width: 100%;\r\n right: -100%;\r\n }\r\n }\r\n `]\r\n})\r\nexport class NotificationPanelComponent implements OnInit, OnDestroy {\r\n @Output() notificationRead = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n\r\n isOpen = false;\r\n notifications: NotificationDto[] = [];\r\n currentTheme: Theme = 'light';\r\n activeTab: 'unread' | 'read' = 'unread'; // Default to unread tab\r\n private destroy$ = new Subject<void>();\r\n\r\n get unreadNotifications(): NotificationDto[] {\r\n return this.notifications.filter(n => !n.isRead);\r\n }\r\n\r\n get readNotifications(): NotificationDto[] {\r\n return this.notifications.filter(n => n.isRead);\r\n }\r\n\r\n get currentNotifications(): NotificationDto[] {\r\n return this.activeTab === 'unread' ? this.unreadNotifications : this.readNotifications;\r\n }\r\n\r\n getNotificationMessage(notification: NotificationDto): string {\r\n return notification.messageHtml || notification.message || '';\r\n }\r\n\r\n constructor(private authService: MesAuthService, private toastService: ToastService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadNotifications();\r\n\r\n // Listen for new real-time notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((notification: RealTimeNotificationDto) => {\r\n // Show toast for new notification\r\n this.toastService.show(\r\n notification.messageHtml || notification.message || '',\r\n notification.title,\r\n 'info',\r\n 5000\r\n );\r\n // Reload notifications list\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n private loadNotifications() {\r\n this.authService.getNotifications(1, 50, true).subscribe({ // includeRead = true to get both read and unread\r\n next: (response: PagedList<NotificationDto>) => {\r\n this.notifications = response.items || [];\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n open() {\r\n this.isOpen = true;\r\n this.activeTab = 'unread'; // Reset to unread tab when opening\r\n }\r\n\r\n close() {\r\n this.isOpen = false;\r\n }\r\n\r\n switchTab(tab: 'unread' | 'read') {\r\n this.activeTab = tab;\r\n }\r\n\r\n markAsRead(notificationId: string, event?: Event) {\r\n if (event) {\r\n event.stopPropagation();\r\n }\r\n this.authService.markAsRead(notificationId).subscribe({\r\n next: () => {\r\n const notification = this.notifications.find(n => n.id === notificationId);\r\n if (notification) {\r\n notification.isRead = true;\r\n this.notificationRead.emit();\r\n }\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n markAllAsRead() {\r\n this.authService.markAllAsRead().subscribe({\r\n next: () => {\r\n this.notifications.forEach(n => n.isRead = true);\r\n this.notificationRead.emit();\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n deleteAllRead() {\r\n const readNotificationIds = this.notifications\r\n .filter(n => n.isRead)\r\n .map(n => n.id);\r\n\r\n // Delete all read notifications\r\n const deletePromises = readNotificationIds.map(id =>\r\n this.authService.deleteNotification(id).toPromise()\r\n );\r\n\r\n Promise.all(deletePromises).then(() => {\r\n // Remove all read notifications from the local array\r\n this.notifications = this.notifications.filter(n => !n.isRead);\r\n }).catch((err) => {\r\n // If bulk delete fails, reload notifications to get current state\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n deleteAllUnread() {\r\n const unreadNotificationIds = this.notifications\r\n .filter(n => !n.isRead)\r\n .map(n => n.id);\r\n\r\n // Delete all unread notifications\r\n const deletePromises = unreadNotificationIds.map(id =>\r\n this.authService.deleteNotification(id).toPromise()\r\n );\r\n\r\n Promise.all(deletePromises).then(() => {\r\n // Remove all unread notifications from the local array\r\n this.notifications = this.notifications.filter(n => n.isRead);\r\n }).catch((err) => {\r\n // If bulk delete fails, reload notifications to get current state\r\n this.loadNotifications();\r\n });\r\n }\r\n\r\n delete(notificationId: string, event: Event) {\r\n event.stopPropagation();\r\n this.authService.deleteNotification(notificationId).subscribe({\r\n next: () => {\r\n this.notifications = this.notifications.filter(n => n.id !== notificationId);\r\n },\r\n error: (err) => {}\r\n });\r\n }\r\n\r\n formatDate(dateString: string): string {\r\n const date = new Date(dateString);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return 'Now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n \r\n return date.toLocaleDateString();\r\n }\r\n}\r\n","import { Component, ViewChild, AfterViewInit } from '@angular/core';\r\nimport { ToastContainerComponent } from './toast-container.component';\r\nimport { UserProfileComponent } from './user-profile.component';\r\nimport { NotificationPanelComponent } from './notification-panel.component';\r\n\r\n@Component({\r\n selector: 'ma-user',\r\n standalone: true,\r\n imports: [ToastContainerComponent, UserProfileComponent, NotificationPanelComponent],\r\n template: `\r\n <ma-toast-container></ma-toast-container>\r\n <div class=\"user-header\">\r\n <ma-user-profile (notificationClick)=\"notificationPanel.open()\"></ma-user-profile>\r\n </div>\r\n <ma-notification-panel #notificationPanel (notificationRead)=\"onNotificationRead()\"></ma-notification-panel>\r\n `,\r\n styles: [`\r\n .user-header {\r\n display: flex;\r\n justify-content: flex-end;\r\n }\r\n `]\r\n})\r\nexport class MaUserComponent implements AfterViewInit {\r\n @ViewChild(UserProfileComponent) userProfile?: UserProfileComponent;\r\n\r\n ngAfterViewInit() {\r\n // Ensure proper initialization\r\n if (this.userProfile) {\r\n this.userProfile.loadUnreadCount();\r\n }\r\n }\r\n\r\n onNotificationRead() {\r\n if (this.userProfile) {\r\n this.userProfile.loadUnreadCount();\r\n }\r\n }\r\n}\r\n","import { Component, OnInit, OnDestroy, Output, EventEmitter, HostBinding } from '@angular/core';\r\nimport { NgIf } from '@angular/common';\r\nimport { MesAuthService } from './mes-auth.service';\r\nimport { ThemeService, Theme } from './theme.service';\r\nimport { Subject } from 'rxjs';\r\nimport { takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'ma-notification-badge',\r\n standalone: true,\r\n imports: [NgIf],\r\n template: `\r\n <button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"unreadCount > 0\">{{ unreadCount }}</span>\r\n </button>\r\n `,\r\n styles: [`\r\n :host {\r\n --error-color: #f44336;\r\n }\r\n\r\n :host(.theme-dark) {\r\n --error-color: #ef5350;\r\n }\r\n\r\n .notification-btn {\r\n position: relative;\r\n background: none;\r\n border: none;\r\n font-size: 24px;\r\n cursor: pointer;\r\n padding: 8px;\r\n transition: opacity 0.2s;\r\n }\r\n\r\n .notification-btn:hover {\r\n opacity: 0.7;\r\n }\r\n\r\n .icon {\r\n display: inline-block;\r\n }\r\n\r\n .badge {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n background-color: var(--error-color);\r\n color: white;\r\n border-radius: 50%;\r\n width: 20px;\r\n height: 20px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n font-weight: bold;\r\n }\r\n `]\r\n})\r\nexport class NotificationBadgeComponent implements OnInit, OnDestroy {\r\n @Output() notificationClick = new EventEmitter<void>();\r\n @HostBinding('class') get themeClass(): string {\r\n return `theme-${this.currentTheme}`;\r\n }\r\n \r\n unreadCount = 0;\r\n currentTheme: Theme = 'light';\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private authService: MesAuthService, private themeService: ThemeService) {}\r\n\r\n ngOnInit() {\r\n this.themeService.currentTheme$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(theme => {\r\n this.currentTheme = theme;\r\n });\r\n\r\n this.loadUnreadCount();\r\n \r\n // Listen for new notifications\r\n this.authService.notifications$\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(() => {\r\n this.loadUnreadCount();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n private loadUnreadCount() {\r\n this.authService.getUnreadCount().subscribe({\r\n next: (response: any) => {\r\n this.unreadCount = response.unreadCount || 0;\r\n },\r\n error: (err) => console.error('Error loading unread count:', err)\r\n });\r\n }\r\n\r\n onNotificationClick() {\r\n this.notificationClick.emit();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.MesAuthService","i3.ThemeService","i1.ToastService","i2.ThemeService","i2.ToastService"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -56,15 +56,51 @@ interface NotificationDto {
|
|
|
56
56
|
}
|
|
57
57
|
interface FrontEndRoute {
|
|
58
58
|
id: number;
|
|
59
|
-
appId: string;
|
|
60
59
|
roleId: string;
|
|
60
|
+
roleName: string;
|
|
61
61
|
routePath: string;
|
|
62
62
|
routeName: string;
|
|
63
63
|
description?: string;
|
|
64
|
+
icon?: string;
|
|
65
|
+
cssClass?: string;
|
|
66
|
+
parentId?: number | null;
|
|
67
|
+
sortOrder: number;
|
|
68
|
+
isLabel: boolean;
|
|
64
69
|
isActive: boolean;
|
|
65
70
|
createdAt: string;
|
|
66
71
|
updatedAt?: string;
|
|
72
|
+
children: FrontEndRoute[];
|
|
73
|
+
}
|
|
74
|
+
interface UserFrontEndRoutesGrouped {
|
|
75
|
+
appId: string;
|
|
76
|
+
appName: string;
|
|
67
77
|
feUrl?: string;
|
|
78
|
+
routes: FrontEndRoute[];
|
|
79
|
+
}
|
|
80
|
+
interface FrontEndRouteMaster {
|
|
81
|
+
id: number;
|
|
82
|
+
appId: string;
|
|
83
|
+
routePath: string;
|
|
84
|
+
routeName: string;
|
|
85
|
+
description?: string;
|
|
86
|
+
icon?: string;
|
|
87
|
+
cssClass?: string;
|
|
88
|
+
parentId?: number | null;
|
|
89
|
+
sortOrder: number;
|
|
90
|
+
isLabel: boolean;
|
|
91
|
+
isActive: boolean;
|
|
92
|
+
createdAt: string;
|
|
93
|
+
updatedAt?: string;
|
|
94
|
+
}
|
|
95
|
+
interface CreateFrontEndRouteDto {
|
|
96
|
+
routePath: string;
|
|
97
|
+
routeName: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
icon?: string;
|
|
100
|
+
cssClass?: string;
|
|
101
|
+
parentId?: number | null;
|
|
102
|
+
sortOrder?: number;
|
|
103
|
+
isLabel?: boolean;
|
|
68
104
|
}
|
|
69
105
|
interface PagedList<T> {
|
|
70
106
|
items: T[];
|
|
@@ -107,8 +143,58 @@ declare class MesAuthService {
|
|
|
107
143
|
markAsRead(notificationId: string): Observable<any>;
|
|
108
144
|
markAllAsRead(): Observable<any>;
|
|
109
145
|
deleteNotification(notificationId: string): Observable<any>;
|
|
110
|
-
|
|
111
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Get frontend routes assigned to the current user
|
|
148
|
+
* Returns routes grouped by application
|
|
149
|
+
*/
|
|
150
|
+
getFrontEndRoutes(): Observable<UserFrontEndRoutesGrouped[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Get master routes for a specific application
|
|
153
|
+
* @param appId - The application ID
|
|
154
|
+
*/
|
|
155
|
+
getRouteMasters(appId: string): Observable<FrontEndRouteMaster[]>;
|
|
156
|
+
/**
|
|
157
|
+
* Register/sync frontend routes for an application
|
|
158
|
+
* This is typically called on app startup to sync routes from the frontend app
|
|
159
|
+
* @param appId - The application ID (passed via X-App-Id header)
|
|
160
|
+
* @param routes - Array of route definitions
|
|
161
|
+
*/
|
|
162
|
+
registerFrontEndRoutes(appId: string, routes: CreateFrontEndRouteDto[]): Observable<any>;
|
|
163
|
+
/**
|
|
164
|
+
* Create a new route master
|
|
165
|
+
* @param appId - The application ID
|
|
166
|
+
* @param route - Route details
|
|
167
|
+
*/
|
|
168
|
+
createRouteMaster(appId: string, route: CreateFrontEndRouteDto): Observable<FrontEndRouteMaster>;
|
|
169
|
+
/**
|
|
170
|
+
* Update an existing route master
|
|
171
|
+
* @param routeId - The route master ID
|
|
172
|
+
* @param route - Updated route details
|
|
173
|
+
*/
|
|
174
|
+
updateRouteMaster(routeId: number, route: Partial<CreateFrontEndRouteDto> & {
|
|
175
|
+
isActive?: boolean;
|
|
176
|
+
}): Observable<FrontEndRouteMaster>;
|
|
177
|
+
/**
|
|
178
|
+
* Delete a route master
|
|
179
|
+
* @param routeId - The route master ID
|
|
180
|
+
*/
|
|
181
|
+
deleteRouteMaster(routeId: number): Observable<any>;
|
|
182
|
+
/**
|
|
183
|
+
* Assign a route to a role
|
|
184
|
+
* @param routeMasterId - The route master ID
|
|
185
|
+
* @param roleId - The role ID (GUID)
|
|
186
|
+
*/
|
|
187
|
+
assignRouteToRole(routeMasterId: number, roleId: string): Observable<any>;
|
|
188
|
+
/**
|
|
189
|
+
* Remove a route assignment from a role
|
|
190
|
+
* @param mappingId - The mapping ID
|
|
191
|
+
*/
|
|
192
|
+
removeRouteFromRole(mappingId: number): Observable<any>;
|
|
193
|
+
/**
|
|
194
|
+
* Get route-to-role mappings for a specific role
|
|
195
|
+
* @param roleId - The role ID (GUID)
|
|
196
|
+
*/
|
|
197
|
+
getRouteMappingsByRole(roleId: string): Observable<any[]>;
|
|
112
198
|
private startConnection;
|
|
113
199
|
stop(): void;
|
|
114
200
|
logout(): Observable<any>;
|
|
@@ -266,4 +352,4 @@ declare class ToastContainerComponent implements OnInit, OnDestroy {
|
|
|
266
352
|
}
|
|
267
353
|
|
|
268
354
|
export { MaUserComponent, MesAuthInterceptor, MesAuthModule, MesAuthService, NotificationBadgeComponent, NotificationPanelComponent, NotificationType, ThemeService, ToastContainerComponent, ToastService, UserProfileComponent };
|
|
269
|
-
export type { FrontEndRoute, IUser, MesAuthConfig, NotificationDto, PagedList, RealTimeNotificationDto, Theme, Toast };
|
|
355
|
+
export type { CreateFrontEndRouteDto, FrontEndRoute, FrontEndRouteMaster, IUser, MesAuthConfig, NotificationDto, PagedList, RealTimeNotificationDto, Theme, Toast, UserFrontEndRoutesGrouped };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mesauth-angular",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.26",
|
|
4
4
|
"description": "Angular helper library to connect to a backend API and SignalR hub to surface the current logged-in user and incoming notifications with dark/light theme support",
|
|
5
5
|
"main": "dist/fesm2022/mesauth-angular.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|