mesauth-angular 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # mesauth-angular
2
+
3
+ Angular helper library to connect to a backend API and SignalR hub to surface the current logged-in user and incoming notifications.
4
+
5
+ Quick start
6
+
7
+ 1. Install (from local folder during development):
8
+
9
+ ```bash
10
+ cd /path/to/your/angular-app
11
+ npm install ../path/to/mesauth-angular
12
+ ```
13
+
14
+ 2. Initialize in your app (e.g. `AppComponent` constructor or `AppModule` bootstrap):
15
+
16
+ ```ts
17
+ // in AppComponent
18
+ constructor(private mesAuth: MesAuthService) {
19
+ this.mesAuth.init({
20
+ signalrUrl: 'https://api.example.com/hubs/notify',
21
+ apiBaseUrl: 'https://api.example.com',
22
+ accessToken: () => localStorage.getItem('access_token')
23
+ });
24
+
25
+ this.mesAuth.currentUser$.subscribe(user => console.log('user', user));
26
+ this.mesAuth.notifications$.subscribe(n => console.log('notif', n));
27
+ }
28
+ ```
29
+
30
+ 3. Build the package for publishing:
31
+
32
+ ```bash
33
+ cd /path/to/mesauth-angular
34
+ npm install
35
+ npm run build
36
+ ```
37
+
38
+ Notes
39
+ - The service expects an endpoint `GET /api/user/current` that returns the current user.
40
+ - SignalR events used: `UserUpdated` and `NewNotification` (adjust to your backend).
@@ -0,0 +1,6 @@
1
+ export * from './mes-auth.service';
2
+ export * from './toast.service';
3
+ export * from './user-profile.component';
4
+ export * from './notification-panel.component';
5
+ export * from './toast-container.component';
6
+ export * from './ma-user.component';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './mes-auth.service';
2
+ export * from './toast.service';
3
+ export * from './user-profile.component';
4
+ export * from './notification-panel.component';
5
+ export * from './toast-container.component';
6
+ export * from './ma-user.component';
@@ -0,0 +1,2 @@
1
+ export declare class MaUserComponent {
2
+ }
@@ -0,0 +1,34 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Component } from '@angular/core';
8
+ import { CommonModule } from '@angular/common';
9
+ import { ToastContainerComponent } from './toast-container.component';
10
+ import { UserProfileComponent } from './user-profile.component';
11
+ import { NotificationPanelComponent } from './notification-panel.component';
12
+ let MaUserComponent = class MaUserComponent {
13
+ };
14
+ MaUserComponent = __decorate([
15
+ Component({
16
+ selector: 'ma-user',
17
+ standalone: true,
18
+ imports: [CommonModule, ToastContainerComponent, UserProfileComponent, NotificationPanelComponent],
19
+ template: `
20
+ <ma-toast-container></ma-toast-container>
21
+ <div class="user-header">
22
+ <ma-user-profile (notificationClick)="notificationPanel.open()"></ma-user-profile>
23
+ </div>
24
+ <ma-notification-panel #notificationPanel></ma-notification-panel>
25
+ `,
26
+ styles: [`
27
+ .user-header {
28
+ display: flex;
29
+ justify-content: flex-end;
30
+ }
31
+ `]
32
+ })
33
+ ], MaUserComponent);
34
+ export { MaUserComponent };
@@ -0,0 +1,97 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
3
+ export interface MesAuthConfig {
4
+ apiBaseUrl: string;
5
+ withCredentials?: boolean;
6
+ avatarUrl?: string;
7
+ userBaseUrl?: string;
8
+ }
9
+ export interface IUser {
10
+ userId?: string;
11
+ userName?: string;
12
+ fullName?: string;
13
+ gender?: string;
14
+ email?: string;
15
+ phoneNumber?: string;
16
+ department?: string;
17
+ position?: string;
18
+ tokenVersion?: string;
19
+ permEndpoint?: string;
20
+ perms?: Set<string>;
21
+ employeeCode?: string;
22
+ hrFullNameVn?: string;
23
+ hrFullNameEn?: string;
24
+ hrPosition?: string;
25
+ hrJobTitle?: string;
26
+ hrGender?: string;
27
+ hrMobile?: string;
28
+ hrEmail?: string;
29
+ hrJoinDate?: string;
30
+ hrBirthDate?: string;
31
+ hrWorkStatus?: string;
32
+ hrDoiTuong?: string;
33
+ hrTeamCode?: string;
34
+ hrLineCode?: string;
35
+ }
36
+ export declare enum NotificationType {
37
+ Info = "Info",
38
+ Warning = "Warning",
39
+ Error = "Error",
40
+ Success = "Success"
41
+ }
42
+ export interface NotificationDto {
43
+ id: string;
44
+ title: string;
45
+ message: string;
46
+ messageHtml?: string;
47
+ url?: string;
48
+ type: NotificationType;
49
+ isRead: boolean;
50
+ createdAt: string;
51
+ sourceAppName: string;
52
+ sourceAppIconUrl?: string;
53
+ }
54
+ export interface PagedList<T> {
55
+ items: T[];
56
+ totalCount: number;
57
+ page: number;
58
+ pageSize: number;
59
+ totalPages: number;
60
+ hasNext: boolean;
61
+ hasPrevious: boolean;
62
+ }
63
+ export interface RealTimeNotificationDto {
64
+ id: string;
65
+ title: string;
66
+ message: string;
67
+ messageHtml?: string;
68
+ url?: string;
69
+ type: NotificationType;
70
+ createdAt: string;
71
+ sourceAppName: string;
72
+ sourceAppIconUrl?: string;
73
+ }
74
+ export declare class MesAuthService {
75
+ private http;
76
+ private hubConnection;
77
+ private _currentUser;
78
+ currentUser$: Observable<IUser | null>;
79
+ private _notifications;
80
+ notifications$: Observable<any>;
81
+ private apiBase;
82
+ private config;
83
+ constructor(http: HttpClient);
84
+ init(config: MesAuthConfig): void;
85
+ getConfig(): MesAuthConfig | null;
86
+ private fetchCurrentUser;
87
+ private fetchInitialNotifications;
88
+ getUnreadCount(): Observable<any>;
89
+ getNotifications(page?: number, pageSize?: number, includeRead?: boolean, type?: string): Observable<any>;
90
+ markAsRead(notificationId: string): Observable<any>;
91
+ markAllAsRead(): Observable<any>;
92
+ deleteNotification(notificationId: string): Observable<any>;
93
+ private startConnection;
94
+ stop(): void;
95
+ logout(): Observable<any>;
96
+ refreshUser(): void;
97
+ }
@@ -0,0 +1,111 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@angular/core';
11
+ import { HttpClient } from '@angular/common/http';
12
+ import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
13
+ import { BehaviorSubject, Subject } from 'rxjs';
14
+ export var NotificationType;
15
+ (function (NotificationType) {
16
+ NotificationType["Info"] = "Info";
17
+ NotificationType["Warning"] = "Warning";
18
+ NotificationType["Error"] = "Error";
19
+ NotificationType["Success"] = "Success";
20
+ })(NotificationType || (NotificationType = {}));
21
+ let MesAuthService = class MesAuthService {
22
+ constructor(http) {
23
+ this.http = http;
24
+ this.hubConnection = null;
25
+ this._currentUser = new BehaviorSubject(null);
26
+ this.currentUser$ = this._currentUser.asObservable();
27
+ this._notifications = new Subject();
28
+ this.notifications$ = this._notifications.asObservable();
29
+ this.apiBase = '';
30
+ this.config = null;
31
+ }
32
+ init(config) {
33
+ this.config = config;
34
+ this.apiBase = config.apiBaseUrl.replace(/\/$/, '');
35
+ this.fetchCurrentUser();
36
+ this.fetchInitialNotifications();
37
+ this.startConnection(config);
38
+ }
39
+ getConfig() {
40
+ return this.config;
41
+ }
42
+ fetchCurrentUser() {
43
+ if (!this.apiBase)
44
+ return;
45
+ this.http.get(`${this.apiBase}/auth/me`).subscribe({
46
+ next: (u) => this._currentUser.next(u),
47
+ error: (err) => console.error('fetchCurrentUser error', err)
48
+ });
49
+ }
50
+ fetchInitialNotifications() {
51
+ if (!this.apiBase)
52
+ return;
53
+ this.http.get(`${this.apiBase}/notif/me`).subscribe({
54
+ next: (notifications) => {
55
+ if (Array.isArray(notifications === null || notifications === void 0 ? void 0 : notifications.items)) {
56
+ notifications.items.forEach((n) => this._notifications.next(n));
57
+ }
58
+ },
59
+ error: (err) => console.error('fetchInitialNotifications error', err)
60
+ });
61
+ }
62
+ getUnreadCount() {
63
+ return this.http.get(`${this.apiBase}/notif/me/unread-count`);
64
+ }
65
+ getNotifications(page = 1, pageSize = 20, includeRead = false, type) {
66
+ let url = `${this.apiBase}/notif/me?page=${page}&pageSize=${pageSize}&includeRead=${includeRead}`;
67
+ if (type) {
68
+ url += `&type=${type}`;
69
+ }
70
+ return this.http.get(url);
71
+ }
72
+ markAsRead(notificationId) {
73
+ return this.http.patch(`${this.apiBase}/notif/${notificationId}/read`, {});
74
+ }
75
+ markAllAsRead() {
76
+ return this.http.patch(`${this.apiBase}/notif/me/read-all`, {});
77
+ }
78
+ deleteNotification(notificationId) {
79
+ return this.http.delete(`${this.apiBase}/notif/${notificationId}`);
80
+ }
81
+ startConnection(config) {
82
+ var _a;
83
+ if (this.hubConnection)
84
+ return;
85
+ const signalrUrl = config.apiBaseUrl.replace(/\/$/, '') + '/hub/notification';
86
+ const builder = new HubConnectionBuilder()
87
+ .withUrl(signalrUrl, { withCredentials: (_a = config.withCredentials) !== null && _a !== void 0 ? _a : true })
88
+ .withAutomaticReconnect()
89
+ .configureLogging(LogLevel.Warning);
90
+ this.hubConnection = builder.build();
91
+ this.hubConnection.on('ReceiveNotification', (n) => this._notifications.next(n));
92
+ this.hubConnection.start().catch((err) => console.error('SignalR start error', err));
93
+ }
94
+ stop() {
95
+ if (!this.hubConnection)
96
+ return;
97
+ this.hubConnection.stop().catch(() => { });
98
+ this.hubConnection = null;
99
+ }
100
+ logout() {
101
+ return this.http.post(`${this.apiBase}/auth/logout`, {});
102
+ }
103
+ refreshUser() {
104
+ this.fetchCurrentUser();
105
+ }
106
+ };
107
+ MesAuthService = __decorate([
108
+ Injectable({ providedIn: 'root' }),
109
+ __metadata("design:paramtypes", [HttpClient])
110
+ ], MesAuthService);
111
+ export { MesAuthService };
@@ -0,0 +1,13 @@
1
+ import { OnInit, OnDestroy, EventEmitter } from '@angular/core';
2
+ import { MesAuthService } from './mes-auth.service';
3
+ export declare class NotificationBadgeComponent implements OnInit, OnDestroy {
4
+ private authService;
5
+ notificationClick: EventEmitter<void>;
6
+ unreadCount: number;
7
+ private destroy$;
8
+ constructor(authService: MesAuthService);
9
+ ngOnInit(): void;
10
+ ngOnDestroy(): void;
11
+ private loadUnreadCount;
12
+ onNotificationClick(): void;
13
+ }
@@ -0,0 +1,100 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Component, Output, EventEmitter } from '@angular/core';
11
+ import { CommonModule } from '@angular/common';
12
+ import { MesAuthService } from './mes-auth.service';
13
+ import { Subject } from 'rxjs';
14
+ import { takeUntil } from 'rxjs/operators';
15
+ let NotificationBadgeComponent = class NotificationBadgeComponent {
16
+ constructor(authService) {
17
+ this.authService = authService;
18
+ this.notificationClick = new EventEmitter();
19
+ this.unreadCount = 0;
20
+ this.destroy$ = new Subject();
21
+ }
22
+ ngOnInit() {
23
+ this.loadUnreadCount();
24
+ // Listen for new notifications
25
+ this.authService.notifications$
26
+ .pipe(takeUntil(this.destroy$))
27
+ .subscribe(() => {
28
+ this.loadUnreadCount();
29
+ });
30
+ }
31
+ ngOnDestroy() {
32
+ this.destroy$.next();
33
+ this.destroy$.complete();
34
+ }
35
+ loadUnreadCount() {
36
+ this.authService.getUnreadCount().subscribe({
37
+ next: (response) => {
38
+ this.unreadCount = response.unreadCount || 0;
39
+ },
40
+ error: (err) => console.error('Error loading unread count:', err)
41
+ });
42
+ }
43
+ onNotificationClick() {
44
+ this.notificationClick.emit();
45
+ }
46
+ };
47
+ __decorate([
48
+ Output(),
49
+ __metadata("design:type", Object)
50
+ ], NotificationBadgeComponent.prototype, "notificationClick", void 0);
51
+ NotificationBadgeComponent = __decorate([
52
+ Component({
53
+ selector: 'ma-notification-badge',
54
+ standalone: true,
55
+ imports: [CommonModule],
56
+ template: `
57
+ <button class="notification-btn" (click)="onNotificationClick()" title="Notifications">
58
+ <span class="icon">🔔</span>
59
+ <span class="badge" *ngIf="unreadCount > 0">{{ unreadCount }}</span>
60
+ </button>
61
+ `,
62
+ styles: [`
63
+ .notification-btn {
64
+ position: relative;
65
+ background: none;
66
+ border: none;
67
+ font-size: 24px;
68
+ cursor: pointer;
69
+ padding: 8px;
70
+ transition: opacity 0.2s;
71
+ }
72
+
73
+ .notification-btn:hover {
74
+ opacity: 0.7;
75
+ }
76
+
77
+ .icon {
78
+ display: inline-block;
79
+ }
80
+
81
+ .badge {
82
+ position: absolute;
83
+ top: 0;
84
+ right: 0;
85
+ background-color: #f44336;
86
+ color: white;
87
+ border-radius: 50%;
88
+ width: 20px;
89
+ height: 20px;
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ font-size: 12px;
94
+ font-weight: bold;
95
+ }
96
+ `]
97
+ }),
98
+ __metadata("design:paramtypes", [MesAuthService])
99
+ ], NotificationBadgeComponent);
100
+ export { NotificationBadgeComponent };
@@ -0,0 +1,20 @@
1
+ import { OnInit, OnDestroy } from '@angular/core';
2
+ import { MesAuthService, NotificationDto } from './mes-auth.service';
3
+ import { ToastService } from './toast.service';
4
+ export declare class NotificationPanelComponent implements OnInit, OnDestroy {
5
+ private authService;
6
+ private toastService;
7
+ isOpen: boolean;
8
+ notifications: NotificationDto[];
9
+ private destroy$;
10
+ constructor(authService: MesAuthService, toastService: ToastService);
11
+ ngOnInit(): void;
12
+ ngOnDestroy(): void;
13
+ private loadNotifications;
14
+ open(): void;
15
+ close(): void;
16
+ markAsRead(notificationId: string): void;
17
+ markAllAsRead(): void;
18
+ delete(notificationId: string, event: Event): void;
19
+ formatDate(dateString: string): string;
20
+ }