@adarshctas/live-notification 0.0.2 → 0.0.3

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 CHANGED
@@ -1,64 +1,89 @@
1
- # LiveNotification
1
+ # @adarshctas/notification1
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.0.
3
+ Angular notification library for showing notifications/messages in Angular applications.
4
4
 
5
- ## Code scaffolding
5
+ ## Installation
6
6
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
7
+ Install the package using npm:
8
8
 
9
9
  ```bash
10
- ng generate component component-name
10
+ npm install @adarshctas/live-notification
11
11
  ```
12
12
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
13
+ ## 🚀 Features
14
+ 🔔 Real-time notifications using Socket.IO
15
+ 📡 REST API support (send / fetch / mark as read)
16
+ 🍞 Toast notifications (success, error, warning, info)
17
+ 📊 Multiple notification modes (alert / toast / in-app)
18
+ 🎯 Filter notifications by type
19
+ ✅ Mark notifications as read
20
+ 🔌 Easy integration in Angular apps
21
+ 🧹 Auto cleanup socket listeners
22
+
23
+ ## Dependencies
24
+
25
+ This package requires:
14
26
 
15
27
  ```bash
16
- ng generate --help
28
+ "@angular/core": ">=15.0.0",
29
+ "@angular/common": ">=15.0.0",
30
+ "@angular/common/http": ">=15.0.0",
31
+ "rxjs": ">=6.5.0"
17
32
  ```
18
33
 
19
- ## Building
34
+ ## How to use
20
35
 
21
- To build the library, run:
36
+ 1 Import the notification service:
22
37
 
23
- ```bash
24
- ng build live-notification
38
+ ```ts
39
+ import { Notification } from '@adarshctas/live-notification';
25
40
  ```
26
41
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
42
+ 2 Use inside component:
43
+
44
+ ```ts
45
+ constructor(private notification: Notification) {}
46
+ ```
28
47
 
29
- ### Publishing the Library
48
+ 3 Initialize (recommended)
30
49
 
31
- Once the project is built, you can publish your library by following these steps:
50
+ ```ts
51
+ ngOnInit() {
32
52
 
33
- 1. Navigate to the `dist` directory:
53
+ this.notification.listenNotification().subscribe(data => {
54
+ console.log('New Notification:', data);
55
+ });
56
+ }
57
+ ```
34
58
 
35
- ```bash
36
- cd dist/live-notification
37
- ```
59
+ ## Example Use Case
38
60
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
61
+ Show a success notification after saving data:
43
62
 
44
- ## Running unit tests
63
+ ```ts
64
+ setToastMode() {
65
+ this.notification.setActiveType('toast');
66
+ }
45
67
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
68
+ setAlertMode() {
69
+ this.notification.setActiveType('alert');
70
+ }
47
71
 
48
- ```bash
49
- ng test
72
+ setInAppMode() {
73
+ this.notification.setActiveType('inapp');
74
+ }
50
75
  ```
51
76
 
52
- ## Running end-to-end tests
77
+ ## 🎯 Summary
53
78
 
54
- For end-to-end (e2e) testing, run:
79
+ show() Simple alert notification
55
80
 
56
- ```bash
57
- ng e2e
58
- ```
81
+ toast() → Temporary popup message
82
+
83
+ notify() → Structured in-app notification
59
84
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
85
+ requestPermission() Browser notification permission
61
86
 
62
- ## Additional Resources
87
+ ## 📄 License
63
88
 
64
- For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
89
+ MIT © Adarsh Ctasis LLP
@@ -1,22 +1,297 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component } from '@angular/core';
2
+ import { Injectable, Component, PLATFORM_ID, Inject } from '@angular/core';
3
+ import { Observable, Subject, interval } from 'rxjs';
4
+ import { io } from 'socket.io-client';
5
+ import * as i1 from '@angular/common/http';
6
+ import * as i2$1 from '@angular/common';
7
+ import { CommonModule, isPlatformBrowser } from '@angular/common';
8
+ import * as i2 from '@angular/forms';
9
+ import { FormsModule } from '@angular/forms';
3
10
 
4
- class LiveNotification {
5
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: LiveNotification, deps: [], target: i0.ɵɵFactoryTarget.Component });
6
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: LiveNotification, isStandalone: true, selector: "lib-live-notification", ngImport: i0, template: ` <p>live-notification works!</p> `, isInline: true, styles: [""] });
11
+ class Notification {
12
+ http;
13
+ receiver;
14
+ /** Used by receiver component to expose a callback for sender actions. */
15
+ registerReceiver(receiver) {
16
+ this.receiver = receiver;
17
+ }
18
+ setActiveType(type) {
19
+ this.receiver?.setActiveType(type);
20
+ }
21
+ static socketInstance;
22
+ socket;
23
+ // BASE URL
24
+ apiUrl = 'http://localhost:3000/api/notifications';
25
+ constructor(http) {
26
+ this.http = http;
27
+ if (!Notification.socketInstance) {
28
+ Notification.socketInstance = io('http://localhost:3000');
29
+ }
30
+ this.socket = Notification.socketInstance;
31
+ }
32
+ // SEND NOTIFICATION
33
+ sendNotification(data) {
34
+ return this.http.post(`${this.apiUrl}/send`, data);
35
+ }
36
+ // GET ALL NOTIFICATIONS
37
+ getAll() {
38
+ return this.http.get(`${this.apiUrl}/all`);
39
+ }
40
+ // REALTIME LISTENER
41
+ listenNotification() {
42
+ return new Observable((observer) => {
43
+ const handler = (data) => observer.next(data);
44
+ this.socket.on('notification', handler);
45
+ return () => {
46
+ this.socket.off('notification', handler);
47
+ };
48
+ });
49
+ }
50
+ listenNotificationByType(type) {
51
+ return new Observable((observer) => {
52
+ const eventName = `notification:${type}`;
53
+ const handler = (data) => observer.next(data);
54
+ this.socket.on(eventName, handler);
55
+ return () => {
56
+ this.socket.off(eventName, handler);
57
+ };
58
+ });
59
+ }
60
+ // MARK AS READ
61
+ markAsRead(id) {
62
+ return this.http.put(`${this.apiUrl}/read/${id}`, { isRead: true });
63
+ }
64
+ toastSubject = new Subject();
65
+ toast$ = this.toastSubject.asObservable();
66
+ emitToast(message, type) {
67
+ this.toastSubject.next({ message, type });
68
+ }
69
+ success(msg) {
70
+ this.emitToast(msg, 'success');
71
+ }
72
+ error(msg) {
73
+ this.emitToast(msg, 'error');
74
+ }
75
+ warning(msg) {
76
+ this.emitToast(msg, 'warning');
77
+ }
78
+ info(msg) {
79
+ this.emitToast(msg, 'info');
80
+ }
81
+ disconnectSocket() {
82
+ if (this.socket) {
83
+ this.socket.disconnect();
84
+ }
85
+ }
86
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: Notification, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
87
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: Notification, providedIn: 'root' });
7
88
  }
8
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: LiveNotification, decorators: [{
89
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: Notification, decorators: [{
90
+ type: Injectable,
91
+ args: [{
92
+ providedIn: 'root',
93
+ }]
94
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
95
+
96
+ class Sender {
97
+ notificationService;
98
+ cd;
99
+ message = '';
100
+ constructor(notificationService, cd) {
101
+ this.notificationService = notificationService;
102
+ this.cd = cd;
103
+ }
104
+ send(type, level = 'INFO') {
105
+ if (!this.message.trim()) {
106
+ return;
107
+ }
108
+ const payload = {
109
+ type: type,
110
+ level: level,
111
+ message: this.message,
112
+ userId: 'global'
113
+ };
114
+ // No realtime updates while typing.
115
+ // Receiver will only update the selected section based on button click.
116
+ this.notificationService.setActiveType?.(type);
117
+ this.notificationService.sendNotification(payload).subscribe({
118
+ next: () => {
119
+ this.message = '';
120
+ },
121
+ error: (err) => {
122
+ console.error('Notification send error:', err);
123
+ }
124
+ });
125
+ }
126
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: Sender, deps: [{ token: Notification }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
127
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: Sender, isStandalone: true, selector: "app-sender", ngImport: i0, template: "<div class=\"sender-container\">\n\n \n <div class=\"card\">\n \n <h2 class=\"title\">\uD83D\uDCE4 Sender Panel</h2>\n\n <p class=\"subtitle\">\n Send real-time notifications instantly\n </p>\n\n <!-- Input -->\n <div class=\"input-box\">\n\n <input\n type=\"text\"\n placeholder=\"Enter notification message...\"\n [(ngModel)]=\"message\"\n (keydown.enter)=\"$event.preventDefault()\"\n />\n\n </div>\n\n <!-- Buttons -->\n <div class=\"btn-group\">\n\n <button\n type=\"button\"\n class=\"alert-btn\"\n (click)=\"send('alert')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83D\uDEA8 Send Alert\n </button>\n\n <button\n type=\"button\"\n class=\"toast-btn\"\n (click)=\"send('toast')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83C\uDF5E Send Toast\n </button>\n<div class=\"btn\">\n <button (click)=\"send('toast', 'SUCCESS')\">Success</button>\n <button (click)=\"send('toast', 'ERROR')\">Error</button>\n <button (click)=\"send('toast', 'WARNING')\">Warning</button>\n <button (click)=\"send('toast', 'INFO')\">Info</button>\n</div>\n <button\n type=\"button\"\n class=\"inapp-btn\"\n (click)=\"send('inapp')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83D\uDD14 Send In-App\n </button>\n\n </div>\n\n </div>\n\n</div>", styles: [".sender-container{min-height:100vh;display:flex;justify-content:center;align-items:center;padding:20px;font-family:Arial,sans-serif}.card{width:420px;background:#fff;padding:25px;border-radius:16px;box-shadow:0 10px 30px #0003;animation:fadeIn .5s ease-in-out}.title{color:#312f2f;text-align:center;font-size:22px;margin-bottom:5px}.subtitle{text-align:center;font-size:13px;color:#666;margin-bottom:20px}.input-box input{width:100%;padding:12px;border-radius:10px;border:1px solid #ddd;outline:none;transition:.3s}.input-box input:focus{border-color:#667eea;box-shadow:0 0 5px #667eea80}.btn-group{display:flex;flex-direction:column;gap:10px;margin-top:15px}button{padding:12px;border:none;border-radius:10px;cursor:pointer;font-weight:700;transition:.3s}.alert-btn{background:#ff4d4dd5}.toast-btn{background:#ffa602d0}.inapp-btn{background:#2ed574c8}button:hover{transform:scale(1.03);opacity:.9}button:disabled{opacity:.5;cursor:not-allowed}@keyframes fadeIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.btn{display:flex;gap:12px;flex-wrap:wrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
128
+ }
129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: Sender, decorators: [{
9
130
  type: Component,
10
- args: [{ selector: 'lib-live-notification', imports: [], template: ` <p>live-notification works!</p> ` }]
11
- }] });
131
+ args: [{ selector: 'app-sender', imports: [CommonModule, FormsModule], template: "<div class=\"sender-container\">\n\n \n <div class=\"card\">\n \n <h2 class=\"title\">\uD83D\uDCE4 Sender Panel</h2>\n\n <p class=\"subtitle\">\n Send real-time notifications instantly\n </p>\n\n <!-- Input -->\n <div class=\"input-box\">\n\n <input\n type=\"text\"\n placeholder=\"Enter notification message...\"\n [(ngModel)]=\"message\"\n (keydown.enter)=\"$event.preventDefault()\"\n />\n\n </div>\n\n <!-- Buttons -->\n <div class=\"btn-group\">\n\n <button\n type=\"button\"\n class=\"alert-btn\"\n (click)=\"send('alert')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83D\uDEA8 Send Alert\n </button>\n\n <button\n type=\"button\"\n class=\"toast-btn\"\n (click)=\"send('toast')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83C\uDF5E Send Toast\n </button>\n<div class=\"btn\">\n <button (click)=\"send('toast', 'SUCCESS')\">Success</button>\n <button (click)=\"send('toast', 'ERROR')\">Error</button>\n <button (click)=\"send('toast', 'WARNING')\">Warning</button>\n <button (click)=\"send('toast', 'INFO')\">Info</button>\n</div>\n <button\n type=\"button\"\n class=\"inapp-btn\"\n (click)=\"send('inapp')\"\n [disabled]=\"!message.trim()\"\n >\n \uD83D\uDD14 Send In-App\n </button>\n\n </div>\n\n </div>\n\n</div>", styles: [".sender-container{min-height:100vh;display:flex;justify-content:center;align-items:center;padding:20px;font-family:Arial,sans-serif}.card{width:420px;background:#fff;padding:25px;border-radius:16px;box-shadow:0 10px 30px #0003;animation:fadeIn .5s ease-in-out}.title{color:#312f2f;text-align:center;font-size:22px;margin-bottom:5px}.subtitle{text-align:center;font-size:13px;color:#666;margin-bottom:20px}.input-box input{width:100%;padding:12px;border-radius:10px;border:1px solid #ddd;outline:none;transition:.3s}.input-box input:focus{border-color:#667eea;box-shadow:0 0 5px #667eea80}.btn-group{display:flex;flex-direction:column;gap:10px;margin-top:15px}button{padding:12px;border:none;border-radius:10px;cursor:pointer;font-weight:700;transition:.3s}.alert-btn{background:#ff4d4dd5}.toast-btn{background:#ffa602d0}.inapp-btn{background:#2ed574c8}button:hover{transform:scale(1.03);opacity:.9}button:disabled{opacity:.5;cursor:not-allowed}@keyframes fadeIn{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.btn{display:flex;gap:12px;flex-wrap:wrap}\n"] }]
132
+ }], ctorParameters: () => [{ type: Notification }, { type: i0.ChangeDetectorRef }] });
12
133
 
13
- /*
14
- * Public API Surface of live-notification
15
- */
134
+ class ReceiverComponent {
135
+ notificationService;
136
+ cd;
137
+ platformId;
138
+ alerts = [];
139
+ toasts = [];
140
+ inapps = [];
141
+ showToast = false;
142
+ liveToastMessage = '';
143
+ toastClass = 'toast-info';
144
+ activeTab = null;
145
+ refreshSub;
146
+ toastSub;
147
+ inappSub;
148
+ alertSub;
149
+ constructor(notificationService, cd, platformId) {
150
+ this.notificationService = notificationService;
151
+ this.cd = cd;
152
+ this.platformId = platformId;
153
+ }
154
+ // =========================
155
+ // INIT
156
+ // =========================
157
+ ngOnInit() {
158
+ this.notificationService.registerReceiver(this);
159
+ this.loadData();
160
+ this.refreshSub = interval(3000).subscribe(() => {
161
+ this.loadData();
162
+ });
163
+ }
164
+ setActiveType(type) {
165
+ this.activeTab = type;
166
+ this.markTabAsRead(type);
167
+ this.cd.detectChanges();
168
+ }
169
+ // =========================
170
+ // LOAD ALL DATA
171
+ // =========================
172
+ loadData() {
173
+ this.notificationService.getAll().subscribe({
174
+ next: (res) => {
175
+ const data = res.data || [];
176
+ this.alerts = data.filter((n) => n.type === 'alert');
177
+ this.toasts = data.filter((n) => n.type === 'toast');
178
+ this.inapps = data.filter((n) => n.type === 'inapp');
179
+ this.cd.detectChanges();
180
+ },
181
+ error: (err) => {
182
+ console.error('Load notification error:', err);
183
+ }
184
+ });
185
+ }
186
+ // =========================
187
+ // AFTER VIEW (REALTIME)
188
+ // =========================
189
+ ngAfterViewInit() {
190
+ if (!isPlatformBrowser(this.platformId))
191
+ return;
192
+ if ('Notification' in window) {
193
+ window.Notification.requestPermission();
194
+ }
195
+ // ALERT
196
+ this.alertSub = this.notificationService
197
+ .listenNotificationByType('alert')
198
+ .subscribe((data) => {
199
+ if (!this.alerts.find(n => n._id === data._id)) {
200
+ this.alerts.unshift(data);
201
+ }
202
+ alert(`🚨 ALERT\n\n${data.message}`);
203
+ this.cd.detectChanges();
204
+ });
205
+ // TOAST
206
+ this.toastSub = this.notificationService
207
+ .listenNotificationByType('toast')
208
+ .subscribe((data) => {
209
+ if (!this.toasts.find(n => n._id === data._id)) {
210
+ this.toasts.unshift(data);
211
+ }
212
+ this.liveToastMessage = data.message;
213
+ this.toastClass = this.getToastClass(data.level);
214
+ this.showToast = true;
215
+ setTimeout(() => {
216
+ this.showToast = false;
217
+ this.cd.detectChanges();
218
+ }, 3000);
219
+ this.cd.detectChanges();
220
+ });
221
+ // INAPP
222
+ this.inappSub = this.notificationService
223
+ .listenNotificationByType('inapp')
224
+ .subscribe((data) => {
225
+ this.inapps.unshift(data);
226
+ if ('Notification' in window &&
227
+ window.Notification.permission === 'granted') {
228
+ new window.Notification('🔔 New Notification', {
229
+ body: data.message,
230
+ });
231
+ }
232
+ this.cd.detectChanges();
233
+ });
234
+ }
235
+ // =========================
236
+ // MARK AS READ (IMPORTANT)
237
+ // =========================
238
+ markTabAsRead(type) {
239
+ let list = [];
240
+ if (type === 'alert')
241
+ list = this.alerts;
242
+ if (type === 'toast')
243
+ list = this.toasts;
244
+ if (type === 'inapp')
245
+ list = this.inapps;
246
+ list.forEach(n => {
247
+ if (!n.isRead) {
248
+ n.isRead = true;
249
+ // backend update (optional)
250
+ this.notificationService.markAsRead(n._id).subscribe({
251
+ error: (err) => console.error(err)
252
+ });
253
+ }
254
+ });
255
+ this.cd.detectChanges();
256
+ }
257
+ // =========================
258
+ // CLEANUP
259
+ // =========================
260
+ ngOnDestroy() {
261
+ this.alertSub?.unsubscribe();
262
+ this.toastSub?.unsubscribe();
263
+ this.inappSub?.unsubscribe();
264
+ this.refreshSub?.unsubscribe();
265
+ this.notificationService.disconnectSocket?.();
266
+ }
267
+ getToastClass(level) {
268
+ switch (level) {
269
+ case 'SUCCESS':
270
+ return 'toast-success';
271
+ case 'ERROR':
272
+ return 'toast-error';
273
+ case 'WARNING':
274
+ return 'toast-warning';
275
+ case 'INFO':
276
+ return 'toast-info';
277
+ default:
278
+ return 'toast-info';
279
+ }
280
+ }
281
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ReceiverComponent, deps: [{ token: Notification }, { token: i0.ChangeDetectorRef }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component });
282
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: ReceiverComponent, isStandalone: true, selector: "lib-receiver", ngImport: i0, template: "<div class=\"receiver-container\">\n\n <!-- BUTTONS -->\n <div class=\"btn-group\">\n\n <button \n [class.active]=\"activeTab === 'alert'\" \n (click)=\"activeTab = 'alert'; markTabAsRead('alert')\">Show Alerts\n <span class=\"badge-count\"\n *ngIf=\"alerts.filter(n => !n.isRead).length > 0\">\n {{ alerts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'toast'\" \n (click)=\"activeTab = 'toast'; markTabAsRead('toast')\">Show Toast\n <span class=\"badge-count\"\n *ngIf=\"toasts.filter(n => !n.isRead).length > 0\">\n {{ toasts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'inapp'\" \n (click)=\"activeTab = 'inapp'; markTabAsRead('inapp')\">Show Notifications\n <span class=\"badge-count\"\n *ngIf=\"inapps.filter(n => !n.isRead).length > 0\">\n {{ inapps.filter(n => !n.isRead).length }}\n </span>\n\n </button>\n\n </div>\n\n <!-- LIVE TOAST -->\n <div class=\"live-toast\" *ngIf=\"showToast\">\n <div class=\"toast-popup\" [class]=\"toastClass\">\n \uD83C\uDF5E {{ liveToastMessage }}\n </div>\n </div>\n\n <div class=\"receiver-card\">\n\n <h2 class=\"title\">\uD83D\uDCE5 Receiver Panel</h2>\n <p class=\"subtitle\">Live incoming notifications</p>\n\n <!-- ALERT -->\n <div class=\"section\" *ngIf=\"activeTab === 'alert'\">\n <h3 class=\"section-title alert-title\">\uD83D\uDEA8 Alerts</h3>\n\n <div *ngFor=\"let n of alerts\">\n <div class=\"notification-card alert\">\n <div class=\"top-row\">\n <div class=\"badge\">ALERT</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- TOAST -->\n <div class=\"section\" *ngIf=\"activeTab === 'toast'\">\n <h3 class=\"section-title toast-title\">\uD83C\uDF5E Toast</h3>\n\n <div *ngFor=\"let n of toasts\">\n <div class=\"notification-card toast\">\n <div class=\"top-row\">\n <div class=\"badge\">TOAST</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- INAPP -->\n <div class=\"section\" *ngIf=\"activeTab === 'inapp'\">\n <h3 class=\"section-title inapp-title\">\uD83D\uDD14 In-App Notifications</h3>\n\n <div *ngFor=\"let n of inapps\">\n <div class=\"notification-card inapp\">\n <div class=\"top-row\">\n <div class=\"badge\">IN-APP</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n </div>\n</div>", styles: [".receiver-container{min-height:100vh;padding:24px;font-family:system-ui,sans-serif;transition:background .3s ease,color .3s ease}.light-theme{background:#f5f7fb;color:#111827}.light-theme .receiver-card{background:#fff;border:1px solid #e5e7eb;color:#111827}.light-theme .btn-group{background:#fff;border:1px solid #e5e7eb}.light-theme .btn-group button{color:#111827;background:transparent}.light-theme .btn-group button:hover{background:#f3f4f6}.light-theme .btn-group button.active{background:#2563eb;color:#fff}.light-theme .notification-card{background:#fff;border:1px solid #e5e7eb;color:#111827}.light-theme .message,.light-theme .time,.light-theme .subtitle{color:#111827}.dark-theme{background:#0b1220;color:#f9fafb}.dark-theme .receiver-card{background:#111827;border:1px solid #1f2937;color:#f9fafb}.dark-theme .btn-group{background:#111827;border:1px solid #1f2937}.dark-theme .btn-group button{color:#d1d5db;background:transparent}.dark-theme .btn-group button:hover{background:#1f2937}.dark-theme .btn-group button.active{background:#3b82f6;color:#fff}.dark-theme .notification-card{background:#0f172a;border:1px solid #1f2937;color:#f9fafb}.dark-theme .message,.dark-theme .time,.dark-theme .subtitle{color:#f9fafb}.btn-group{display:flex;gap:12px;padding:10px;border-radius:12px;width:fit-content;margin:0 auto 20px}.btn-group button{position:relative;border:none;padding:10px 16px;border-radius:10px;cursor:pointer;font-weight:600;transition:all .2s ease}.badge-count{position:absolute;top:-6px;right:-6px;background:#ef4444;color:#fff;font-size:11px;width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center}.receiver-card{max-width:900px;margin:auto;padding:20px;border-radius:14px}.notification-card{padding:14px;border-radius:10px;margin-bottom:12px;transition:transform .2s ease}.notification-card:hover{transform:translateY(-2px)}.message{font-size:14px;line-height:1.5;word-break:break-word}.time{font-size:12px}.receiver-card{max-width:900px;margin:auto;padding:22px;border-radius:16px;transition:all .3s ease;background:#ffffff05;box-shadow:0 10px 25px #00000040,0 0 0 1px #ffffff0a,0 0 40px #3b82f626}.receiver-card:hover{transform:translateY(-3px);box-shadow:0 15px 35px #00000059,0 0 0 1px #ffffff0f,0 0 60px #6366f140}.dark-theme .receiver-card{background:#0f172a;box-shadow:0 15px 40px #0009,0 0 0 1px #ffffff0d,0 0 50px #3b82f633}.light-theme .receiver-card{background:#fff;box-shadow:0 10px 25px #00000014,0 0 0 1px #0000000d,0 0 30px #3b82f614}.notification-card.alert{border-left:4px solid #ef4444;background:#ef44440f;box-shadow:0 8px 20px #00000040,0 0 0 1px #ef444426,0 0 25px #ef444440}.notification-card.alert:hover{transform:translateY(-3px);box-shadow:0 12px 30px #00000059,0 0 0 1px #ef444440,0 0 40px #ef444466}.notification-card.toast{border-left:4px solid #f59e0b;background:#f59e0b0f;box-shadow:0 8px 20px #00000038,0 0 0 1px #f59e0b2e,0 0 25px #f59e0b38}.notification-card.toast:hover{transform:translateY(-3px);box-shadow:0 12px 30px #0000004d,0 0 0 1px #f59e0b4d,0 0 40px #f59e0b59}.notification-card.inapp{border-left:4px solid #3b82f6;background:#3b82f60f;box-shadow:0 8px 20px #00000038,0 0 0 1px #3b82f62e,0 0 25px #3b82f638}.notification-card.inapp:hover{transform:translateY(-3px);box-shadow:0 12px 30px #0000004d,0 0 0 1px #3b82f64d,0 0 40px #3b82f659}.receiver-container{padding:20px;min-height:100vh;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif}.btn-group{display:flex;gap:12px;margin-bottom:20px;flex-wrap:wrap}.btn-group button{position:relative;padding:10px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.1);background:#ffffff0f;cursor:pointer;transition:.25s ease;font-weight:500;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.btn-group button:hover{transform:translateY(-2px);background:#ffffff1a}.btn-group button.active{background:linear-gradient(135deg,#6366f1,#3b82f6);border:none;box-shadow:0 10px 25px #3b82f64d}.badge-count{margin-left:8px;background:#ef4444;color:#fff;font-size:12px;padding:2px 7px;border-radius:999px;position:absolute;top:-6px;right:-6px;box-shadow:0 4px 10px #0000004d}.live-toast{position:fixed;top:20px;right:20px;z-index:999}.toast-popup{padding:12px 16px;border-radius:12px;font-weight:500;animation:slideIn .3s ease;box-shadow:0 10px 25px #0000004d}.toast-popup.success{background:#22c55e}.toast-popup.error{background:#ef4444}.toast-popup.warning{background:#f59e0b}.toast-popup.info{background:#3b82f6}@keyframes slideIn{0%{transform:translate(120%);opacity:0}to{transform:translate(0);opacity:1}}.receiver-card{background:#ffffff0d;border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:20px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 15px 40px #0006}.title{font-size:22px;font-weight:600}.subtitle{font-size:14px;opacity:.7;margin-bottom:16px}.section{margin-top:10px}.section-title{margin-bottom:12px;font-size:16px;font-weight:600}.alert-title{color:#f87171}.toast-title{color:#fbbf24}.inapp-title{color:#60a5fa}.notification-card{padding:14px;border-radius:14px;margin-bottom:12px;border:1px solid rgba(255,255,255,.08);background:#ffffff0a;transition:.2s ease}.notification-card:hover{transform:scale(1.02);background:#ffffff12}.notification-card.alert{border-left:4px solid #ef4444}.notification-card.toast{border-left:4px solid #f59e0b}.notification-card.inapp{border-left:4px solid #3b82f6}.top-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.badge{font-size:11px;padding:3px 8px;border-radius:999px;background:#ffffff1a;letter-spacing:.5px}.time{font-size:11px;opacity:.6}.message{font-size:14px;line-height:1.4;opacity:.9}.toast-success{background:#22c55e;color:#fff}.toast-error{background:#ef4444;color:#fff}.toast-warning{background:#f59e0b;color:#fff}.toast-info{background:#3b82f6;color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2$1.DatePipe, name: "date" }] });
283
+ }
284
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ReceiverComponent, decorators: [{
285
+ type: Component,
286
+ args: [{ selector: 'lib-receiver', standalone: true, imports: [CommonModule], template: "<div class=\"receiver-container\">\n\n <!-- BUTTONS -->\n <div class=\"btn-group\">\n\n <button \n [class.active]=\"activeTab === 'alert'\" \n (click)=\"activeTab = 'alert'; markTabAsRead('alert')\">Show Alerts\n <span class=\"badge-count\"\n *ngIf=\"alerts.filter(n => !n.isRead).length > 0\">\n {{ alerts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'toast'\" \n (click)=\"activeTab = 'toast'; markTabAsRead('toast')\">Show Toast\n <span class=\"badge-count\"\n *ngIf=\"toasts.filter(n => !n.isRead).length > 0\">\n {{ toasts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'inapp'\" \n (click)=\"activeTab = 'inapp'; markTabAsRead('inapp')\">Show Notifications\n <span class=\"badge-count\"\n *ngIf=\"inapps.filter(n => !n.isRead).length > 0\">\n {{ inapps.filter(n => !n.isRead).length }}\n </span>\n\n </button>\n\n </div>\n\n <!-- LIVE TOAST -->\n <div class=\"live-toast\" *ngIf=\"showToast\">\n <div class=\"toast-popup\" [class]=\"toastClass\">\n \uD83C\uDF5E {{ liveToastMessage }}\n </div>\n </div>\n\n <div class=\"receiver-card\">\n\n <h2 class=\"title\">\uD83D\uDCE5 Receiver Panel</h2>\n <p class=\"subtitle\">Live incoming notifications</p>\n\n <!-- ALERT -->\n <div class=\"section\" *ngIf=\"activeTab === 'alert'\">\n <h3 class=\"section-title alert-title\">\uD83D\uDEA8 Alerts</h3>\n\n <div *ngFor=\"let n of alerts\">\n <div class=\"notification-card alert\">\n <div class=\"top-row\">\n <div class=\"badge\">ALERT</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- TOAST -->\n <div class=\"section\" *ngIf=\"activeTab === 'toast'\">\n <h3 class=\"section-title toast-title\">\uD83C\uDF5E Toast</h3>\n\n <div *ngFor=\"let n of toasts\">\n <div class=\"notification-card toast\">\n <div class=\"top-row\">\n <div class=\"badge\">TOAST</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- INAPP -->\n <div class=\"section\" *ngIf=\"activeTab === 'inapp'\">\n <h3 class=\"section-title inapp-title\">\uD83D\uDD14 In-App Notifications</h3>\n\n <div *ngFor=\"let n of inapps\">\n <div class=\"notification-card inapp\">\n <div class=\"top-row\">\n <div class=\"badge\">IN-APP</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n </div>\n</div>", styles: [".receiver-container{min-height:100vh;padding:24px;font-family:system-ui,sans-serif;transition:background .3s ease,color .3s ease}.light-theme{background:#f5f7fb;color:#111827}.light-theme .receiver-card{background:#fff;border:1px solid #e5e7eb;color:#111827}.light-theme .btn-group{background:#fff;border:1px solid #e5e7eb}.light-theme .btn-group button{color:#111827;background:transparent}.light-theme .btn-group button:hover{background:#f3f4f6}.light-theme .btn-group button.active{background:#2563eb;color:#fff}.light-theme .notification-card{background:#fff;border:1px solid #e5e7eb;color:#111827}.light-theme .message,.light-theme .time,.light-theme .subtitle{color:#111827}.dark-theme{background:#0b1220;color:#f9fafb}.dark-theme .receiver-card{background:#111827;border:1px solid #1f2937;color:#f9fafb}.dark-theme .btn-group{background:#111827;border:1px solid #1f2937}.dark-theme .btn-group button{color:#d1d5db;background:transparent}.dark-theme .btn-group button:hover{background:#1f2937}.dark-theme .btn-group button.active{background:#3b82f6;color:#fff}.dark-theme .notification-card{background:#0f172a;border:1px solid #1f2937;color:#f9fafb}.dark-theme .message,.dark-theme .time,.dark-theme .subtitle{color:#f9fafb}.btn-group{display:flex;gap:12px;padding:10px;border-radius:12px;width:fit-content;margin:0 auto 20px}.btn-group button{position:relative;border:none;padding:10px 16px;border-radius:10px;cursor:pointer;font-weight:600;transition:all .2s ease}.badge-count{position:absolute;top:-6px;right:-6px;background:#ef4444;color:#fff;font-size:11px;width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center}.receiver-card{max-width:900px;margin:auto;padding:20px;border-radius:14px}.notification-card{padding:14px;border-radius:10px;margin-bottom:12px;transition:transform .2s ease}.notification-card:hover{transform:translateY(-2px)}.message{font-size:14px;line-height:1.5;word-break:break-word}.time{font-size:12px}.receiver-card{max-width:900px;margin:auto;padding:22px;border-radius:16px;transition:all .3s ease;background:#ffffff05;box-shadow:0 10px 25px #00000040,0 0 0 1px #ffffff0a,0 0 40px #3b82f626}.receiver-card:hover{transform:translateY(-3px);box-shadow:0 15px 35px #00000059,0 0 0 1px #ffffff0f,0 0 60px #6366f140}.dark-theme .receiver-card{background:#0f172a;box-shadow:0 15px 40px #0009,0 0 0 1px #ffffff0d,0 0 50px #3b82f633}.light-theme .receiver-card{background:#fff;box-shadow:0 10px 25px #00000014,0 0 0 1px #0000000d,0 0 30px #3b82f614}.notification-card.alert{border-left:4px solid #ef4444;background:#ef44440f;box-shadow:0 8px 20px #00000040,0 0 0 1px #ef444426,0 0 25px #ef444440}.notification-card.alert:hover{transform:translateY(-3px);box-shadow:0 12px 30px #00000059,0 0 0 1px #ef444440,0 0 40px #ef444466}.notification-card.toast{border-left:4px solid #f59e0b;background:#f59e0b0f;box-shadow:0 8px 20px #00000038,0 0 0 1px #f59e0b2e,0 0 25px #f59e0b38}.notification-card.toast:hover{transform:translateY(-3px);box-shadow:0 12px 30px #0000004d,0 0 0 1px #f59e0b4d,0 0 40px #f59e0b59}.notification-card.inapp{border-left:4px solid #3b82f6;background:#3b82f60f;box-shadow:0 8px 20px #00000038,0 0 0 1px #3b82f62e,0 0 25px #3b82f638}.notification-card.inapp:hover{transform:translateY(-3px);box-shadow:0 12px 30px #0000004d,0 0 0 1px #3b82f64d,0 0 40px #3b82f659}.receiver-container{padding:20px;min-height:100vh;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif}.btn-group{display:flex;gap:12px;margin-bottom:20px;flex-wrap:wrap}.btn-group button{position:relative;padding:10px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.1);background:#ffffff0f;cursor:pointer;transition:.25s ease;font-weight:500;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.btn-group button:hover{transform:translateY(-2px);background:#ffffff1a}.btn-group button.active{background:linear-gradient(135deg,#6366f1,#3b82f6);border:none;box-shadow:0 10px 25px #3b82f64d}.badge-count{margin-left:8px;background:#ef4444;color:#fff;font-size:12px;padding:2px 7px;border-radius:999px;position:absolute;top:-6px;right:-6px;box-shadow:0 4px 10px #0000004d}.live-toast{position:fixed;top:20px;right:20px;z-index:999}.toast-popup{padding:12px 16px;border-radius:12px;font-weight:500;animation:slideIn .3s ease;box-shadow:0 10px 25px #0000004d}.toast-popup.success{background:#22c55e}.toast-popup.error{background:#ef4444}.toast-popup.warning{background:#f59e0b}.toast-popup.info{background:#3b82f6}@keyframes slideIn{0%{transform:translate(120%);opacity:0}to{transform:translate(0);opacity:1}}.receiver-card{background:#ffffff0d;border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:20px;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:0 15px 40px #0006}.title{font-size:22px;font-weight:600}.subtitle{font-size:14px;opacity:.7;margin-bottom:16px}.section{margin-top:10px}.section-title{margin-bottom:12px;font-size:16px;font-weight:600}.alert-title{color:#f87171}.toast-title{color:#fbbf24}.inapp-title{color:#60a5fa}.notification-card{padding:14px;border-radius:14px;margin-bottom:12px;border:1px solid rgba(255,255,255,.08);background:#ffffff0a;transition:.2s ease}.notification-card:hover{transform:scale(1.02);background:#ffffff12}.notification-card.alert{border-left:4px solid #ef4444}.notification-card.toast{border-left:4px solid #f59e0b}.notification-card.inapp{border-left:4px solid #3b82f6}.top-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.badge{font-size:11px;padding:3px 8px;border-radius:999px;background:#ffffff1a;letter-spacing:.5px}.time{font-size:11px;opacity:.6}.message{font-size:14px;line-height:1.4;opacity:.9}.toast-success{background:#22c55e;color:#fff}.toast-error{background:#ef4444;color:#fff}.toast-warning{background:#f59e0b;color:#fff}.toast-info{background:#3b82f6;color:#fff}\n"] }]
287
+ }], ctorParameters: () => [{ type: Notification }, { type: i0.ChangeDetectorRef }, { type: Object, decorators: [{
288
+ type: Inject,
289
+ args: [PLATFORM_ID]
290
+ }] }] });
16
291
 
17
292
  /**
18
293
  * Generated bundle index. Do not edit.
19
294
  */
20
295
 
21
- export { LiveNotification };
296
+ export { Notification, ReceiverComponent, Sender };
22
297
  //# sourceMappingURL=adarshctas-live-notification.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"adarshctas-live-notification.mjs","sources":["../../../projects/live-notification/src/lib/live-notification.ts","../../../projects/live-notification/src/public-api.ts","../../../projects/live-notification/src/adarshctas-live-notification.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-live-notification',\n imports: [],\n template: ` <p>live-notification works!</p> `,\n styles: ``,\n})\nexport class LiveNotification {}\n","/*\n * Public API Surface of live-notification\n */\n\nexport * from './lib/live-notification';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAQa,gBAAgB,CAAA;wGAAhB,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,gBAAgB,iFAHjB,CAAA,iCAAA,CAAmC,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAGlC,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAN5B,SAAS;+BACE,uBAAuB,EAAA,OAAA,EACxB,EAAE,EAAA,QAAA,EACD,CAAA,iCAAA,CAAmC,EAAA;;;ACL/C;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"adarshctas-live-notification.mjs","sources":["../../../projects/live-notification/src/lib/services/notification.ts","../../../projects/live-notification/src/lib/sender/sender.ts","../../../projects/live-notification/src/lib/sender/sender.html","../../../projects/live-notification/src/lib/receiver/receiver.ts","../../../projects/live-notification/src/lib/receiver/receiver.html","../../../projects/live-notification/src/adarshctas-live-notification.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Observable,Subject } from 'rxjs';\nimport { io, Socket } from 'socket.io-client';\n\nexport type ToastType = 'success' | 'error' | 'warning' | 'info';\n\nexport interface Toast {\n message: string;\n type: ToastType;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class Notification {\n\n private receiver?: { setActiveType: (type: 'alert' | 'toast' | 'inapp') => void };\n\n /** Used by receiver component to expose a callback for sender actions. */\n registerReceiver(receiver: { setActiveType: (type: 'alert' | 'toast' | 'inapp') => void }) {\n this.receiver = receiver;\n }\n\n setActiveType(type: 'alert' | 'toast' | 'inapp') {\n this.receiver?.setActiveType(type);\n }\n\n private static socketInstance: Socket;\nprivate socket: Socket;\n\n // BASE URL\n private apiUrl = 'http://localhost:3000/api/notifications';\n\n constructor(private http: HttpClient) { if (!Notification.socketInstance) {\n Notification.socketInstance = io('http://localhost:3000');\n }\n\n this.socket = Notification.socketInstance; }\n\n // SEND NOTIFICATION\n sendNotification(data: any): Observable<any> {\n\n return this.http.post(\n `${this.apiUrl}/send`,\n data\n );\n\n }\n\n // GET ALL NOTIFICATIONS\n getAll(): Observable<any> {\n\n return this.http.get(\n `${this.apiUrl}/all`\n );\n\n }\n\n // REALTIME LISTENER\nlistenNotification(): Observable<any> {\n return new Observable((observer) => {\n\n const handler = (data: any) => observer.next(data);\n\n this.socket.on('notification', handler);\n\n return () => {\n this.socket.off('notification', handler);\n };\n\n });\n}\n\n listenNotificationByType(type: string): Observable<any> {\n return new Observable((observer) => {\n const eventName = `notification:${type}`;\n const handler = (data: any) => observer.next(data);\n\n this.socket.on(eventName, handler);\n\n return () => {\n this.socket.off(eventName, handler);\n };\n });\n }\n // MARK AS READ\n markAsRead(id: string): Observable<any> {\n return this.http.put(\n `${this.apiUrl}/read/${id}`,\n { isRead: true }\n );\n }\n private toastSubject = new Subject<Toast>();\ntoast$ = this.toastSubject.asObservable();\n\nprivate emitToast(message: string, type: ToastType) {\n this.toastSubject.next({ message, type });\n}\n\nsuccess(msg: string) {\n this.emitToast(msg, 'success');\n}\n\nerror(msg: string) {\n this.emitToast(msg, 'error');\n}\n\nwarning(msg: string) {\n this.emitToast(msg, 'warning');\n}\n\ninfo(msg: string) {\n this.emitToast(msg, 'info');\n}\n\ndisconnectSocket() {\n if (this.socket) {\n this.socket.disconnect();\n }\n}\n} \n","import { Component, ChangeDetectorRef } from '@angular/core';\nimport { Notification } from '../services/notification';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\n@Component({\n selector: 'app-sender',\n imports: [CommonModule, FormsModule],\n templateUrl: './sender.html',\n styleUrl: './sender.css',\n})\nexport class Sender {\n\n message = '';\n\n constructor(\n private notificationService: Notification,\n private cd: ChangeDetectorRef\n ) {}\n\nsend(type: string, level: string = 'INFO') {\n\n if (!this.message.trim()) {\n return;\n }\n\n const payload = {\n type:type,\n level: level,\n message: this.message,\n userId: 'global'\n };\n\n\n // No realtime updates while typing.\n // Receiver will only update the selected section based on button click.\n (this.notificationService as any).setActiveType?.(type);\n\n\n this.notificationService.sendNotification(payload).subscribe({\n\n next: () => {\n this.message = '';\n\n },\n\n error: (err) => {\n console.error('Notification send error:', err);\n\n }\n });\n\n }\n \n}","<div class=\"sender-container\">\n\n \n <div class=\"card\">\n \n <h2 class=\"title\">📤 Sender Panel</h2>\n\n <p class=\"subtitle\">\n Send real-time notifications instantly\n </p>\n\n <!-- Input -->\n <div class=\"input-box\">\n\n <input\n type=\"text\"\n placeholder=\"Enter notification message...\"\n [(ngModel)]=\"message\"\n (keydown.enter)=\"$event.preventDefault()\"\n />\n\n </div>\n\n <!-- Buttons -->\n <div class=\"btn-group\">\n\n <button\n type=\"button\"\n class=\"alert-btn\"\n (click)=\"send('alert')\"\n [disabled]=\"!message.trim()\"\n >\n 🚨 Send Alert\n </button>\n\n <button\n type=\"button\"\n class=\"toast-btn\"\n (click)=\"send('toast')\"\n [disabled]=\"!message.trim()\"\n >\n 🍞 Send Toast\n </button>\n<div class=\"btn\">\n <button (click)=\"send('toast', 'SUCCESS')\">Success</button>\n <button (click)=\"send('toast', 'ERROR')\">Error</button>\n <button (click)=\"send('toast', 'WARNING')\">Warning</button>\n <button (click)=\"send('toast', 'INFO')\">Info</button>\n</div>\n <button\n type=\"button\"\n class=\"inapp-btn\"\n (click)=\"send('inapp')\"\n [disabled]=\"!message.trim()\"\n >\n 🔔 Send In-App\n </button>\n\n </div>\n\n </div>\n\n</div>","import {\n Component,\n OnInit,\n OnDestroy,\n AfterViewInit,\n ChangeDetectorRef,\n Inject,\n PLATFORM_ID,\n \n} from '@angular/core';\n\nimport { CommonModule, isPlatformBrowser } from '@angular/common';\nimport { Notification } from '../services/notification';\nimport { interval, Subscription } from 'rxjs';\n\n@Component({\n selector: 'lib-receiver',\n standalone: true,\n imports: [CommonModule],\n templateUrl: './receiver.html',\n styleUrl: './receiver.css',\n})\nexport class ReceiverComponent implements OnInit, OnDestroy, AfterViewInit {\n\n alerts: any[] = [];\n toasts: any[] = [];\n inapps: any[] = [];\n\n showToast = false;\n liveToastMessage = '';\n toastClass = 'toast-info';\n\nactiveTab: 'alert' | 'toast' | 'inapp' | null = null;\n\n private refreshSub?: Subscription;\n private toastSub?: Subscription;\n private inappSub?: Subscription;\n private alertSub?: Subscription;\n\n constructor(\n private notificationService: Notification,\n private cd: ChangeDetectorRef,\n @Inject(PLATFORM_ID) private platformId: Object\n ) {}\n\n // =========================\n // INIT\n // =========================\n ngOnInit(): void {\n this.notificationService.registerReceiver(this);\n this.loadData();\n\n this.refreshSub = interval(3000).subscribe(() => {\n this.loadData();\n });\n }\n\n setActiveType(type: 'alert' | 'toast' | 'inapp'): void {\n this.activeTab = type;\n this.markTabAsRead(type);\n this.cd.detectChanges();\n }\n\n // =========================\n // LOAD ALL DATA\n // =========================\n loadData(): void {\n this.notificationService.getAll().subscribe({\n next: (res: any) => {\n const data = res.data || [];\n\n this.alerts = data.filter((n: any) => n.type === 'alert');\n this.toasts = data.filter((n: any) => n.type === 'toast');\n this.inapps = data.filter((n: any) => n.type === 'inapp');\n\n this.cd.detectChanges();\n },\n error: (err: any) => {\n console.error('Load notification error:', err);\n }\n });\n }\n\n // =========================\n // AFTER VIEW (REALTIME)\n // =========================\n ngAfterViewInit(): void {\n if (!isPlatformBrowser(this.platformId)) return;\n\n if ('Notification' in window) {\n window.Notification.requestPermission();\n }\n\n // ALERT\n this.alertSub = this.notificationService\n .listenNotificationByType('alert')\n .subscribe((data: any) => {\n if (!this.alerts.find(n => n._id === data._id)) {\n this.alerts.unshift(data);\n }\n\n alert(`🚨 ALERT\\n\\n${data.message}`);\n this.cd.detectChanges();\n });\n\n // TOAST\n this.toastSub = this.notificationService\n .listenNotificationByType('toast')\n .subscribe((data: any) => {\n\n if (!this.toasts.find(n => n._id === data._id)) {\n this.toasts.unshift(data);\n }\n\n this.liveToastMessage = data.message;\n this.toastClass = this.getToastClass(data.level);\n this.showToast = true;\n\n setTimeout(() => {\n this.showToast = false;\n this.cd.detectChanges();\n }, 3000);\n\n this.cd.detectChanges();\n });\n\n // INAPP\n this.inappSub = this.notificationService\n .listenNotificationByType('inapp')\n .subscribe((data: any) => {\n\n this.inapps.unshift(data);\n\n if (\n 'Notification' in window &&\n window.Notification.permission === 'granted'\n ) {\n new window.Notification('🔔 New Notification', {\n body: data.message,\n });\n }\n\n this.cd.detectChanges();\n });\n }\n\n // =========================\n // MARK AS READ (IMPORTANT)\n // =========================\n markTabAsRead(type: string): void {\n let list: any[] = [];\n\n if (type === 'alert') list = this.alerts;\n if (type === 'toast') list = this.toasts;\n if (type === 'inapp') list = this.inapps;\n\n list.forEach(n => {\n if (!n.isRead) {\n n.isRead = true;\n\n // backend update (optional)\n this.notificationService.markAsRead(n._id).subscribe({\n error: (err: any) => console.error(err)\n });\n }\n });\n\n this.cd.detectChanges();\n }\n\n // =========================\n // CLEANUP\n // =========================\nngOnDestroy(): void {\n this.alertSub?.unsubscribe();\n this.toastSub?.unsubscribe();\n this.inappSub?.unsubscribe();\n this.refreshSub?.unsubscribe();\n\n this.notificationService.disconnectSocket?.();\n}\n\ngetToastClass(level: string) {\n switch (level) {\n\n case 'SUCCESS':\n return 'toast-success';\n\n case 'ERROR':\n return 'toast-error';\n\n case 'WARNING':\n return 'toast-warning';\n\n case 'INFO':\n return 'toast-info';\n\n default:\n return 'toast-info';\n }\n}\n\n}","<div class=\"receiver-container\">\n\n <!-- BUTTONS -->\n <div class=\"btn-group\">\n\n <button \n [class.active]=\"activeTab === 'alert'\" \n (click)=\"activeTab = 'alert'; markTabAsRead('alert')\">Show Alerts\n <span class=\"badge-count\"\n *ngIf=\"alerts.filter(n => !n.isRead).length > 0\">\n {{ alerts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'toast'\" \n (click)=\"activeTab = 'toast'; markTabAsRead('toast')\">Show Toast\n <span class=\"badge-count\"\n *ngIf=\"toasts.filter(n => !n.isRead).length > 0\">\n {{ toasts.filter(n => !n.isRead).length }}\n </span>\n </button>\n\n <button \n [class.active]=\"activeTab === 'inapp'\" \n (click)=\"activeTab = 'inapp'; markTabAsRead('inapp')\">Show Notifications\n <span class=\"badge-count\"\n *ngIf=\"inapps.filter(n => !n.isRead).length > 0\">\n {{ inapps.filter(n => !n.isRead).length }}\n </span>\n\n </button>\n\n </div>\n\n <!-- LIVE TOAST -->\n <div class=\"live-toast\" *ngIf=\"showToast\">\n <div class=\"toast-popup\" [class]=\"toastClass\">\n 🍞 {{ liveToastMessage }}\n </div>\n </div>\n\n <div class=\"receiver-card\">\n\n <h2 class=\"title\">📥 Receiver Panel</h2>\n <p class=\"subtitle\">Live incoming notifications</p>\n\n <!-- ALERT -->\n <div class=\"section\" *ngIf=\"activeTab === 'alert'\">\n <h3 class=\"section-title alert-title\">🚨 Alerts</h3>\n\n <div *ngFor=\"let n of alerts\">\n <div class=\"notification-card alert\">\n <div class=\"top-row\">\n <div class=\"badge\">ALERT</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- TOAST -->\n <div class=\"section\" *ngIf=\"activeTab === 'toast'\">\n <h3 class=\"section-title toast-title\">🍞 Toast</h3>\n\n <div *ngFor=\"let n of toasts\">\n <div class=\"notification-card toast\">\n <div class=\"top-row\">\n <div class=\"badge\">TOAST</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n <!-- INAPP -->\n <div class=\"section\" *ngIf=\"activeTab === 'inapp'\">\n <h3 class=\"section-title inapp-title\">🔔 In-App Notifications</h3>\n\n <div *ngFor=\"let n of inapps\">\n <div class=\"notification-card inapp\">\n <div class=\"top-row\">\n <div class=\"badge\">IN-APP</div>\n <small class=\"time\">{{ n.createdAt | date:'short' }}</small>\n </div>\n <p class=\"message\">{{ n.message }}</p>\n </div>\n </div>\n </div>\n\n </div>\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.Notification","i2"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adarshctas/live-notification",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.2.0",
6
6
  "@angular/core": "^21.2.0"
@@ -1,8 +1,78 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { Observable } from 'rxjs';
1
3
  import * as i0 from '@angular/core';
4
+ import { ChangeDetectorRef, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
2
5
 
3
- declare class LiveNotification {
4
- static ɵfac: i0.ɵɵFactoryDeclaration<LiveNotification, never>;
5
- static ɵcmp: i0.ɵɵComponentDeclaration<LiveNotification, "lib-live-notification", never, {}, {}, never, never, true, never>;
6
+ type ToastType = 'success' | 'error' | 'warning' | 'info';
7
+ interface Toast {
8
+ message: string;
9
+ type: ToastType;
10
+ }
11
+ declare class Notification {
12
+ private http;
13
+ private receiver?;
14
+ /** Used by receiver component to expose a callback for sender actions. */
15
+ registerReceiver(receiver: {
16
+ setActiveType: (type: 'alert' | 'toast' | 'inapp') => void;
17
+ }): void;
18
+ setActiveType(type: 'alert' | 'toast' | 'inapp'): void;
19
+ private static socketInstance;
20
+ private socket;
21
+ private apiUrl;
22
+ constructor(http: HttpClient);
23
+ sendNotification(data: any): Observable<any>;
24
+ getAll(): Observable<any>;
25
+ listenNotification(): Observable<any>;
26
+ listenNotificationByType(type: string): Observable<any>;
27
+ markAsRead(id: string): Observable<any>;
28
+ private toastSubject;
29
+ toast$: Observable<Toast>;
30
+ private emitToast;
31
+ success(msg: string): void;
32
+ error(msg: string): void;
33
+ warning(msg: string): void;
34
+ info(msg: string): void;
35
+ disconnectSocket(): void;
36
+ static ɵfac: i0.ɵɵFactoryDeclaration<Notification, never>;
37
+ static ɵprov: i0.ɵɵInjectableDeclaration<Notification>;
38
+ }
39
+
40
+ declare class Sender {
41
+ private notificationService;
42
+ private cd;
43
+ message: string;
44
+ constructor(notificationService: Notification, cd: ChangeDetectorRef);
45
+ send(type: string, level?: string): void;
46
+ static ɵfac: i0.ɵɵFactoryDeclaration<Sender, never>;
47
+ static ɵcmp: i0.ɵɵComponentDeclaration<Sender, "app-sender", never, {}, {}, never, never, true, never>;
48
+ }
49
+
50
+ declare class ReceiverComponent implements OnInit, OnDestroy, AfterViewInit {
51
+ private notificationService;
52
+ private cd;
53
+ private platformId;
54
+ alerts: any[];
55
+ toasts: any[];
56
+ inapps: any[];
57
+ showToast: boolean;
58
+ liveToastMessage: string;
59
+ toastClass: string;
60
+ activeTab: 'alert' | 'toast' | 'inapp' | null;
61
+ private refreshSub?;
62
+ private toastSub?;
63
+ private inappSub?;
64
+ private alertSub?;
65
+ constructor(notificationService: Notification, cd: ChangeDetectorRef, platformId: Object);
66
+ ngOnInit(): void;
67
+ setActiveType(type: 'alert' | 'toast' | 'inapp'): void;
68
+ loadData(): void;
69
+ ngAfterViewInit(): void;
70
+ markTabAsRead(type: string): void;
71
+ ngOnDestroy(): void;
72
+ getToastClass(level: string): "toast-info" | "toast-success" | "toast-error" | "toast-warning";
73
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReceiverComponent, never>;
74
+ static ɵcmp: i0.ɵɵComponentDeclaration<ReceiverComponent, "lib-receiver", never, {}, {}, never, never, true, never>;
6
75
  }
7
76
 
8
- export { LiveNotification };
77
+ export { Notification, ReceiverComponent, Sender };
78
+ export type { Toast, ToastType };