@arthakosh/chat-widget 0.2.29 → 0.2.32

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, signal, Inject, Injectable, EventEmitter, input, inject, ViewChild, Output, Input, Component, effect, ViewEncapsulation, computed, NgModule } from '@angular/core';
2
+ import { InjectionToken, Inject, Injectable, signal, EventEmitter, input, inject, ViewChild, Output, Input, Component, effect, ViewEncapsulation, computed, NgModule } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i2 from '@angular/forms';
@@ -30,99 +30,6 @@ import { trigger, transition, style, animate } from '@angular/animations';
30
30
  // chat.tokens.ts
31
31
  const CHAT_CONFIG = new InjectionToken('CHAT_CONFIG');
32
32
 
33
- class ChatService {
34
- constructor(http, config) {
35
- this.http = http;
36
- this.config = config;
37
- // private baseUrl = `https://coreuatarthkosh.sarjak.com`;
38
- this.currentUser = signal(null);
39
- this.userList = signal([]);
40
- this.archiveRoomId = signal('');
41
- this.notifications = signal([]);
42
- this.hasNewNotification = signal(false);
43
- }
44
- get baseUrl() {
45
- return this.config.apiBaseUrl;
46
- }
47
- /* ---------------- CHAT ROOMS ---------------- */
48
- createRoom(roomId, name, metadata, createdBy, username, chatUsers) {
49
- return this.http.post(`${this.baseUrl}/api/chat/chatrooms/create/${roomId}/`, {
50
- name,
51
- metadata,
52
- createdBy,
53
- username,
54
- chatUsers
55
- });
56
- }
57
- getRoomUsers(roomId) {
58
- return this.http.get(`${this.baseUrl}/api/chat/chatrooms/get_user/${roomId}/users/`).pipe(map(list => list.map(u => ({
59
- id: u.UserId,
60
- username: u.UserName
61
- }))));
62
- }
63
- addUserToRoom(roomId, userId, userName, createdBy) {
64
- return this.http.post(`${this.baseUrl}/api/chat/chatrooms/add_user/${roomId}/users/add/`, {
65
- userId,
66
- userName,
67
- createdBy
68
- });
69
- }
70
- /* ---------------- MESSAGES ---------------- */
71
- getMessages(roomId, since) {
72
- const params = {};
73
- if (since)
74
- params.since = since;
75
- return this.http.get(`${this.baseUrl}/api/chat/messages/rooms/all_messages/${roomId}/`, { params }).pipe(map(list => list.map(m => ({
76
- id: m.id,
77
- chatRoomId: m.chatRoomId,
78
- senderId: m.senderId,
79
- senderName: m.senderName,
80
- content: m.content,
81
- replyToMessageId: m.replyToMessageId,
82
- createdAt: m.createdAt,
83
- hasAttachment: m.hasAttachment ?? false,
84
- }))));
85
- }
86
- sendMessage(roomId, payload) {
87
- return this.http.post(`${this.baseUrl}/api/chat/messages/rooms/send/${roomId}/`, payload).pipe(map(m => ({
88
- id: m.id,
89
- chatRoomId: m.chatRoomId,
90
- senderId: m.senderId,
91
- senderName: m.senderName,
92
- content: m.content,
93
- replyToMessageId: m.replyToMessageId,
94
- createdAt: m.createdAt,
95
- hasAttachment: m.hasAttachment ?? false,
96
- })));
97
- }
98
- getRooms(loggedInUserId, chatRoomId) {
99
- let url = `${this.baseUrl}/api/chat/chatrooms/${loggedInUserId}`;
100
- if (chatRoomId) {
101
- url += `/${chatRoomId}`;
102
- }
103
- return this.http.get(`${url}/`);
104
- }
105
- archiveRoom(roomId) {
106
- return this.http.delete(`${this.baseUrl}/api/chat/chatrooms/archive/${roomId}/`);
107
- }
108
- notifyArrival() {
109
- this.hasNewNotification.set(true);
110
- // auto-reset after animation
111
- setTimeout(() => {
112
- this.hasNewNotification.set(false);
113
- }, 1200);
114
- }
115
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, deps: [{ token: i1.HttpClient }, { token: CHAT_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
116
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, providedIn: 'root' }); }
117
- }
118
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, decorators: [{
119
- type: Injectable,
120
- args: [{ providedIn: 'root' }]
121
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
122
- type: Inject,
123
- args: [CHAT_CONFIG]
124
- }] }] });
125
-
126
33
  class SocketService {
127
34
  constructor(config) {
128
35
  this.config = config;
@@ -214,6 +121,156 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
214
121
  args: [CHAT_CONFIG]
215
122
  }] }] });
216
123
 
124
+ class ChatService {
125
+ constructor(http, config, socket) {
126
+ this.http = http;
127
+ this.config = config;
128
+ this.socket = socket;
129
+ // private baseUrl = `https://coreuatarthkosh.sarjak.com`;
130
+ this.currentUser = signal(null);
131
+ this.userList = signal([]);
132
+ this.archiveRoomId = signal('');
133
+ this.notifications = signal([]);
134
+ this.hasNewNotification = signal(false);
135
+ this.listenForNotifications();
136
+ }
137
+ get baseUrl() {
138
+ return this.config.apiBaseUrl;
139
+ }
140
+ /* ---------------- CHAT ROOMS ---------------- */
141
+ createRoom(roomId, name, metadata, createdBy, username, chatUsers) {
142
+ return this.http.post(`${this.baseUrl}/api/chat/chatrooms/create/${roomId}/`, {
143
+ name,
144
+ metadata,
145
+ createdBy,
146
+ username,
147
+ chatUsers
148
+ });
149
+ }
150
+ getRoomUsers(roomId) {
151
+ return this.http.get(`${this.baseUrl}/api/chat/chatrooms/get_user/${roomId}/users/`).pipe(map(list => list.map(u => ({
152
+ id: u.UserId,
153
+ username: u.UserName
154
+ }))));
155
+ }
156
+ addUserToRoom(roomId, userId, userName, createdBy) {
157
+ return this.http.post(`${this.baseUrl}/api/chat/chatrooms/add_user/${roomId}/users/add/`, {
158
+ userId,
159
+ userName,
160
+ createdBy
161
+ });
162
+ }
163
+ /* ---------------- MESSAGES ---------------- */
164
+ getMessages(roomId, since) {
165
+ const params = {};
166
+ if (since)
167
+ params.since = since;
168
+ return this.http.get(`${this.baseUrl}/api/chat/messages/rooms/all_messages/${roomId}/`, { params }).pipe(map(list => list.map(m => ({
169
+ id: m.id,
170
+ chatRoomId: m.chatRoomId,
171
+ senderId: m.senderId,
172
+ senderName: m.senderName,
173
+ content: m.content,
174
+ replyToMessageId: m.replyToMessageId,
175
+ createdAt: m.createdAt,
176
+ hasAttachment: m.hasAttachment ?? false,
177
+ }))));
178
+ }
179
+ sendMessage(roomId, payload) {
180
+ return this.http.post(`${this.baseUrl}/api/chat/messages/rooms/send/${roomId}/`, payload).pipe(map(m => ({
181
+ id: m.id,
182
+ chatRoomId: m.chatRoomId,
183
+ senderId: m.senderId,
184
+ senderName: m.senderName,
185
+ content: m.content,
186
+ replyToMessageId: m.replyToMessageId,
187
+ createdAt: m.createdAt,
188
+ hasAttachment: m.hasAttachment ?? false,
189
+ })));
190
+ }
191
+ getRooms(loggedInUserId, chatRoomId) {
192
+ let url = `${this.baseUrl}/api/chat/chatrooms/${loggedInUserId}`;
193
+ if (chatRoomId) {
194
+ url += `/${chatRoomId}`;
195
+ }
196
+ return this.http.get(`${url}/`);
197
+ }
198
+ archiveRoom(roomId) {
199
+ return this.http.delete(`${this.baseUrl}/api/chat/chatrooms/archive/${roomId}/`);
200
+ }
201
+ listenForNotifications() {
202
+ // 🔔 ADDED TO ROOM — only added user
203
+ this.socket.on('addedToRoom').subscribe((msg) => {
204
+ if (msg.addedUserId !== this.currentUser().userId)
205
+ return;
206
+ this.upsertNotification({
207
+ roomId: msg.chatRoomId,
208
+ roomName: msg.roomName,
209
+ type: 'added'
210
+ });
211
+ });
212
+ // 🔔 NEW MESSAGE — everyone EXCEPT sender
213
+ this.socket.on('newMessage').subscribe((msg) => {
214
+ if (msg.senderId === this.currentUser().userId)
215
+ return;
216
+ this.upsertNotification({
217
+ roomId: msg.chatRoomId,
218
+ type: 'message',
219
+ lastMessage: msg.content
220
+ });
221
+ });
222
+ }
223
+ upsertNotification(data) {
224
+ this.notifications.update(list => {
225
+ const index = list.findIndex(n => n.roomId === data.roomId);
226
+ if (index !== -1) {
227
+ const n = list[index];
228
+ list[index] = {
229
+ ...n,
230
+ unreadCount: n.unreadCount + 1,
231
+ lastMessage: data.lastMessage ?? n.lastMessage,
232
+ timestamp: Date.now()
233
+ };
234
+ return [...list];
235
+ }
236
+ return [
237
+ ...list,
238
+ {
239
+ roomId: data.roomId,
240
+ roomName: data.roomName,
241
+ type: data.type,
242
+ unreadCount: 1,
243
+ lastMessage: data.lastMessage,
244
+ timestamp: Date.now()
245
+ }
246
+ ];
247
+ });
248
+ this.notifyArrival();
249
+ }
250
+ clearRoom(roomId) {
251
+ this.notifications.update(list => list.filter(n => n.roomId !== roomId));
252
+ }
253
+ clearAll() {
254
+ this.notifications.set([]);
255
+ }
256
+ notifyArrival() {
257
+ this.hasNewNotification.set(true);
258
+ // auto-reset after animation
259
+ setTimeout(() => {
260
+ this.hasNewNotification.set(false);
261
+ }, 1200);
262
+ }
263
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, deps: [{ token: i1.HttpClient }, { token: CHAT_CONFIG }, { token: SocketService }], target: i0.ɵɵFactoryTarget.Injectable }); }
264
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, providedIn: 'root' }); }
265
+ }
266
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatService, decorators: [{
267
+ type: Injectable,
268
+ args: [{ providedIn: 'root' }]
269
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
270
+ type: Inject,
271
+ args: [CHAT_CONFIG]
272
+ }] }, { type: SocketService }] });
273
+
217
274
  class ChatWindowComponent {
218
275
  constructor() {
219
276
  this.header = 'Chat';
@@ -265,12 +322,6 @@ class ChatWindowComponent {
265
322
  this.socket.on('newMessage').subscribe(msg => {
266
323
  if (msg.chatRoomId === this.chatRoomId) {
267
324
  this.messages.update(list => [...list, msg]);
268
- this.upsertNotification({
269
- roomId: msg.chatRoomId,
270
- // roomName: msg.roomName,
271
- type: 'message',
272
- // lastMessage: msg.message
273
- });
274
325
  }
275
326
  // if (msg.senderId !== this.chatService.currentUser().userId) {
276
327
  // this.messageService.add({
@@ -296,11 +347,6 @@ class ChatWindowComponent {
296
347
  if (msg.chatRoomId === this.chatRoomId) {
297
348
  this.loadUsers();
298
349
  console.log('addedToRoom', msg);
299
- this.upsertNotification({
300
- roomId: msg.chatRoomId,
301
- roomName: msg.roomName,
302
- type: 'added'
303
- });
304
350
  }
305
351
  });
306
352
  this.socket.on('userAlreadyInRoom').subscribe((msg) => {
@@ -376,39 +422,6 @@ class ChatWindowComponent {
376
422
  closeChat() {
377
423
  this.onClose.emit();
378
424
  }
379
- upsertNotification(data) {
380
- this.chatService.notifications.update(list => {
381
- const index = list.findIndex(n => n.roomId === data.roomId);
382
- if (index !== -1) {
383
- const n = list[index];
384
- list[index] = {
385
- ...n,
386
- unreadCount: n.unreadCount + 1,
387
- lastMessage: data.lastMessage ?? n.lastMessage,
388
- timestamp: Date.now()
389
- };
390
- return [...list];
391
- }
392
- return [
393
- ...list,
394
- {
395
- roomId: data.roomId,
396
- roomName: data.roomName,
397
- type: data.type,
398
- unreadCount: 1,
399
- lastMessage: data.lastMessage,
400
- timestamp: Date.now()
401
- }
402
- ];
403
- });
404
- this.chatService.notifyArrival();
405
- }
406
- clearRoom(roomId) {
407
- this.chatService.notifications.update(list => list.filter(n => n.roomId !== roomId));
408
- }
409
- clearAll() {
410
- this.chatService.notifications.set([]);
411
- }
412
425
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
413
426
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ChatWindowComponent, isStandalone: true, selector: "app-chat-window", inputs: { chatRoomId: { classPropertyName: "chatRoomId", publicName: "chatRoomId", isSignal: false, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: false, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: false, isRequired: false, transformFunction: null }, chatUsers: { classPropertyName: "chatUsers", publicName: "chatUsers", isSignal: false, isRequired: false, transformFunction: null }, showActions: { classPropertyName: "showActions", publicName: "showActions", isSignal: false, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: false, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: false, isRequired: false, transformFunction: null }, refreshRoom: { classPropertyName: "refreshRoom", publicName: "refreshRoom", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onArchive: "onArchive", onClose: "onClose" }, providers: [MessageService], viewQueries: [{ propertyName: "messagesContainer", first: true, predicate: ["messagesContainer"], descendants: true }, { propertyName: "reactionOverlay", first: true, predicate: ["reactionOverlay"], descendants: true }], ngImport: i0, template: "<p-toast></p-toast>\r\n\r\n<div [class.dark]=\"theme === 'dark'\" [class.floating]=\"mode === 'floating'\" [class.fullscreen]=\"mode === 'fullscreen'\"\r\n [class.minimized]=\"minimized\" class=\"chat-window\">\r\n <div class=\"chat-header\">\r\n <div style=\"display: flex; flex-direction: column;\">\r\n <div class=\"title\">\r\n <span>{{ header }}</span>\r\n <span *ngIf=\"users().length\">({{ users().length }} {{\r\n users().length == 1 ? 'participant' :\r\n 'participants'\r\n }})</span>\r\n </div>\r\n <div>\r\n <span>{{ metadata }}</span>\r\n </div>\r\n </div>\r\n <div class=\"header-actions\">\r\n <button (click)=\"toggleUsers()\" icon=\"pi pi-users\" pButton pTooltip=\"Toogle Users\"\r\n style=\"font-size: 0.5rem\"></button>\r\n @if (showActions) {\r\n <button (click)=\"toggleMinimize()\" [icon]=\"minimized ? 'pi pi-plus' : 'pi pi-minus'\" pButton\r\n pTooltip=\"Hide/Show\" style=\"font-size: 0.5rem\"></button>\r\n <button (click)=\"archiveChat()\" icon=\"pi pi-trash\" pButton pTooltip=\"Archive\"\r\n style=\"font-size: 0.5rem\"></button>\r\n <button (click)=\"closeChat()\" icon=\"pi pi-times\" pButton pTooltip=\"Close\"\r\n style=\"font-size: 0.5rem\"></button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"!minimized\" class=\"chat-body\">\r\n <div [class.users-hidden]=\"!showUsers\" class=\"chat-layout\">\r\n <div [class.floating]=\"mode === 'floating'\" [class.fullscreen]=\"mode === 'fullscreen'\" class=\"chat-main\">\r\n <div #messagesContainer [class.loading]=\"loading\" class=\"messages\">\r\n <div *ngFor=\"let msg of messages(); trackBy: trackById\" [ngClass]=\"{ outgoing: msg.senderId === chatService.currentUser().userId, incoming: msg.senderId !== chatService.currentUser().userId }\"\r\n class=\"message-row\">\r\n <div class=\"message-bubble\">\r\n <div class=\"message-meta\">\r\n <span class=\"sender\">\r\n <!-- *ngIf=\"msg.senderId !== chatService.currentUser().userId\" -->\r\n {{ msg.senderName }}\r\n </span>\r\n <!-- <span class=\"time\">\r\n {{ msg.createdAt | date: 'shortTime' }}\r\n </span> -->\r\n </div>\r\n\r\n <!-- MESSAGE TEXT -->\r\n <div class=\"message-content\">\r\n {{ msg.content }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"input-area\">\r\n <div *ngIf=\"replyTo\" class=\"reply-banner\">\r\n <span>Replying to: {{ replyTo.content | slice: 0:50 }}</span>\r\n <button (click)=\"clearReply()\" class=\"p-button-text p-button-sm\" icon=\"pi pi-times\"\r\n pButton></button>\r\n </div>\r\n\r\n <textarea (keyup.enter)=\"send()\" [(ngModel)]=\"newMessage\" autoResize=\"true\" pInputTextarea\r\n placeholder=\"Type a message\"\r\n rows=\"2\">\r\n </textarea>\r\n\r\n <div class=\"input-actions\">\r\n <button (click)=\"send()\" icon=\"pi pi-send\" label=\"Send\" pButton></button>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"chat-sidebar\">\r\n <div class=\"section-title\">Users</div>\r\n <div class=\"user-list\">\r\n <div *ngFor=\"let u of users()\" class=\"user-row\">\r\n <p-avatar [label]=\"u.username[0]\"></p-avatar>\r\n <span>{{ u.username }}</span>\r\n </div>\r\n </div>\r\n @if (showActions) {\r\n <div class=\"user-list-add\">\r\n <p-dropdown [(ngModel)]=\"selectedUser\" [options]=\"chatService.userList()\"\r\n optionLabel=\"full_name\"\r\n placeholder=\"Select User\"/>\r\n <div style=\"margin-top: 2em;\">\r\n <button (click)=\"addUserToRoom()\" icon=\"pi pi-plus\" label=\"Add\" pButton></button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".chat-window{width:35vw;max-width:95vw;display:flex;flex-direction:column;background:#fff;border-radius:16px;box-shadow:0 8px 30px #0000001f;overflow:visible;font-size:14px;font-family:Inter,system-ui,sans-serif}.chat-window.minimized{height:auto}.chat-header{display:flex;align-items:center;justify-content:space-between;background:#4f6ef7;color:#fff;padding:10px 14px}.chat-header .title{display:flex;flex-direction:row;gap:6px}.chat-header .title span{font-weight:600;font-size:14px}.chat-header .title small{font-size:11px;opacity:.85}.chat-body{display:flex;flex:1;background:#f5f7fb}.chat-layout{display:flex;flex:1;width:100%;overflow:hidden}.chat-layout.users-hidden .chat-sidebar{transform:translate(100%);opacity:0;pointer-events:none;width:0!important}.chat-layout.users-hidden .chat-main{flex:1 1 100%}.chat-main{flex:1;display:flex;flex-direction:column;background:#f5f7fb;height:70vh}.messages{flex:1;padding:16px 14px;overflow-y:auto;scroll-behavior:smooth}.message-row{display:flex;margin-bottom:14px;animation:messageIn .25s ease-out;position:relative;overflow:visible;padding-top:28px}@keyframes messageIn{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.message-row.incoming{justify-content:flex-start}.message-row.incoming .reaction-bar{left:12px}.message-row.outgoing{justify-content:flex-end}.message-row.outgoing .reaction-bar{right:12px;left:auto}.message-bubble{position:relative;max-width:72%;padding:10px 14px;border-radius:16px;font-size:14px;line-height:1.45;word-break:break-word;overflow:visible}.message-row.incoming .message-bubble{background:#fff;color:#111;border-top-left-radius:6px;box-shadow:0 3px 10px #0000000f;overflow:visible}.message-bubble:after{content:\"\";position:absolute;bottom:-6px;right:8px}.message-row.incoming .message-bubble:after{content:\"\";position:absolute;left:-6px;top:12px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-right:6px solid #ffffff}.message-row.outgoing .message-bubble{background:#4f6ef7;color:#fff;border-top-right-radius:6px;overflow:visible}.message-row.outgoing .message-bubble:after{content:\"\";position:absolute;right:-6px;top:12px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-left:6px solid #4f6ef7}.message-meta{display:flex;justify-content:flex-end;font-size:10px;opacity:.6;margin-bottom:4px}.typing-indicator{display:inline-flex;align-items:center;gap:4px;padding:8px 12px;background:#fff;border-radius:14px;box-shadow:0 2px 6px #00000014}.typing-indicator span{width:6px;height:6px;background:#999;border-radius:50%;animation:typingDots 1.4s infinite ease-in-out both}.typing-indicator span:nth-child(1){animation-delay:0s}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}@keyframes typingDots{0%{transform:translateY(0);opacity:.4}50%{transform:translateY(-4px);opacity:1}to{transform:translateY(0);opacity:.4}}.input-area{background:#fff;padding:10px;border:1px solid #e5e7eb;display:flex;flex-direction:row;justify-content:space-between;gap:5px}.input-area textarea{max-height:60px;overflow:hidden;width:-webkit-fill-available}.reply-banner{background:#eef2ff;border-left:3px solid #4f6ef7;padding:6px 8px;font-size:12px;border-radius:8px;margin-bottom:6px;display:flex;justify-content:space-between}.input-actions{display:flex;justify-content:flex-end;margin-top:6px}.input-actions button{background:#4f6ef7;color:#fff;border-radius:999px;padding:0 16px}.chat-sidebar{background:#fff;border-left:1px solid #e5e7eb;box-shadow:-4px 0 10px #0000000d;display:flex;flex-direction:column}.section-title{font-weight:600;font-size:13px;padding:10px;border-bottom:1px solid #e5e7eb}.user-list{flex:1;overflow-y:auto;padding:8px;max-height:20em}.user-row{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:8px}.user-row:hover{background:#f1f5f9}.user-list-add{padding:10px;border-top:1px solid #e5e7eb}.header-actions{display:flex;align-items:center;gap:6px}.header-actions .p-button{width:32px;height:32px;padding:0;border-radius:50%;background:#ffffff26}.header-actions .p-button:hover{background:#ffffff40}.chat-header{min-height:48px}.header-actions{flex-shrink:0}.header-actions .p-button{transition:background .2s ease,transform .1s ease}.header-actions .p-button:active{transform:scale(.92)}.reaction-bar{position:absolute;top:0;left:12px;transform:translateY(-100%);background:#fff;border-radius:20px;padding:4px 8px;display:none;box-shadow:0 2px 8px #0003;z-index:9999}.message-bubble:hover .reaction-bar{display:flex}.reaction-bar span{cursor:pointer;font-size:16px}.reaction-summary{margin-top:4px;display:flex;gap:6px}.reaction-chip{background:#f1f1f1;padding:2px 6px;border-radius:12px;font-size:12px;position:relative}.reaction-users-tooltip{position:absolute;bottom:130%;left:50%;transform:translate(-50%);white-space:nowrap;background:#222;color:#fff;padding:4px 8px;border-radius:6px;z-index:10000;bottom:calc(100% + 6px)}.message-row,.message-bubble,.reaction-summary{overflow:visible!important}.p-tooltip{z-index:9999!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1$1.SlicePipe, name: "slice" }, { 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"] }, { kind: "ngmodule", type: ToastModule }, { kind: "component", type: i3.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i4.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i5.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "style", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: InputTextareaModule }, { kind: "directive", type: i7.InputTextarea, selector: "[pInputTextarea]", inputs: ["autoResize", "variant"], outputs: ["onResize"] }, { kind: "ngmodule", type: ChipModule }, { kind: "ngmodule", type: DropdownModule }, { kind: "component", type: i8.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "autoShowPanelOnPrintableCharacterKeyDown", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: OverlayPanelModule }] }); }
414
427
  }
@@ -645,11 +658,14 @@ class ChatWidgetNotificationComponent {
645
658
  this.open = !this.open;
646
659
  }
647
660
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatWidgetNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
648
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ChatWidgetNotificationComponent, isStandalone: true, selector: "chat-widget-notification", ngImport: i0, template: "<div (click)=\"toggle()\" class=\"notif-icon\">\r\n <i [class.pulse]=\"hasNew()\" class=\"pi pi-bell\">\r\n </i>\r\n\r\n @if (totalCount() > 0) {\r\n <span class=\"dot\"></span>\r\n <span class=\"badge\">\r\n {{ totalCount() }}\r\n </span>\r\n }\r\n</div>\r\n\r\n@if (open) {\r\n <div class=\"notif-panel\">\r\n @for (n of notifications(); track n.roomId) {\r\n <div class=\"notif-item\">\r\n <strong>{{ n.roomName }}</strong>\r\n <p>{{ n.lastMessage || 'You were added to this room' }}</p>\r\n <span class=\"count\">{{ n.unreadCount }}</span>\r\n </div>\r\n }\r\n </div>\r\n}", styles: [".notif-wrapper{position:relative;cursor:pointer}.pi-bell{font-size:1.4rem}.pi-bell.pulse{animation:pulse 1.2s ease-out}@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.2)}to{transform:scale(1)}}.dot{position:absolute;top:0;right:2px;width:8px;height:8px;background:red;border-radius:50%}.badge{position:absolute;top:-6px;right:-10px;background:red;color:#fff;font-size:.65rem;padding:2px 6px;border-radius:10px}\n"] }); }
661
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ChatWidgetNotificationComponent, isStandalone: true, selector: "chat-widget-notification", ngImport: i0, template: "<div (click)=\"toggle()\" class=\"notif-icon\">\r\n <i [class.pulse]=\"hasNew()\" class=\"pi pi-bell\">\r\n </i>\r\n\r\n @if (totalCount() > 0) {\r\n <span class=\"dot\"></span>\r\n <span class=\"badge\">\r\n {{ totalCount() }}\r\n </span>\r\n }\r\n</div>\r\n\r\n@if (open) {\r\n <div class=\"notif-panel\">\r\n @for (n of notifications(); track n.roomId) {\r\n <div class=\"notif-item\">\r\n <strong>{{ n.roomName }}</strong>\r\n <p>{{ n.lastMessage || 'You were added to this room' }}</p>\r\n <span class=\"count\">{{ n.unreadCount }}</span>\r\n </div>\r\n }\r\n </div>\r\n}", styles: [".notif-wrapper{position:relative;cursor:pointer}.pi-bell{font-size:1.4rem}.pi-bell.pulse{animation:pulse 1.2s ease-out}@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.2)}to{transform:scale(1)}}.dot{position:absolute;top:0;right:2px;width:8px;height:8px;background:red;border-radius:50%}.badge{position:absolute;top:-6px;right:-10px;background:red;color:#fff;font-size:.65rem;padding:2px 6px;border-radius:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] }); }
649
662
  }
650
663
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatWidgetNotificationComponent, decorators: [{
651
664
  type: Component,
652
- args: [{ selector: 'chat-widget-notification', standalone: true, imports: [], template: "<div (click)=\"toggle()\" class=\"notif-icon\">\r\n <i [class.pulse]=\"hasNew()\" class=\"pi pi-bell\">\r\n </i>\r\n\r\n @if (totalCount() > 0) {\r\n <span class=\"dot\"></span>\r\n <span class=\"badge\">\r\n {{ totalCount() }}\r\n </span>\r\n }\r\n</div>\r\n\r\n@if (open) {\r\n <div class=\"notif-panel\">\r\n @for (n of notifications(); track n.roomId) {\r\n <div class=\"notif-item\">\r\n <strong>{{ n.roomName }}</strong>\r\n <p>{{ n.lastMessage || 'You were added to this room' }}</p>\r\n <span class=\"count\">{{ n.unreadCount }}</span>\r\n </div>\r\n }\r\n </div>\r\n}", styles: [".notif-wrapper{position:relative;cursor:pointer}.pi-bell{font-size:1.4rem}.pi-bell.pulse{animation:pulse 1.2s ease-out}@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.2)}to{transform:scale(1)}}.dot{position:absolute;top:0;right:2px;width:8px;height:8px;background:red;border-radius:50%}.badge{position:absolute;top:-6px;right:-10px;background:red;color:#fff;font-size:.65rem;padding:2px 6px;border-radius:10px}\n"] }]
665
+ args: [{ selector: 'chat-widget-notification', standalone: true, imports: [
666
+ CommonModule,
667
+ FormsModule
668
+ ], template: "<div (click)=\"toggle()\" class=\"notif-icon\">\r\n <i [class.pulse]=\"hasNew()\" class=\"pi pi-bell\">\r\n </i>\r\n\r\n @if (totalCount() > 0) {\r\n <span class=\"dot\"></span>\r\n <span class=\"badge\">\r\n {{ totalCount() }}\r\n </span>\r\n }\r\n</div>\r\n\r\n@if (open) {\r\n <div class=\"notif-panel\">\r\n @for (n of notifications(); track n.roomId) {\r\n <div class=\"notif-item\">\r\n <strong>{{ n.roomName }}</strong>\r\n <p>{{ n.lastMessage || 'You were added to this room' }}</p>\r\n <span class=\"count\">{{ n.unreadCount }}</span>\r\n </div>\r\n }\r\n </div>\r\n}", styles: [".notif-wrapper{position:relative;cursor:pointer}.pi-bell{font-size:1.4rem}.pi-bell.pulse{animation:pulse 1.2s ease-out}@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.2)}to{transform:scale(1)}}.dot{position:absolute;top:0;right:2px;width:8px;height:8px;background:red;border-radius:50%}.badge{position:absolute;top:-6px;right:-10px;background:red;color:#fff;font-size:.65rem;padding:2px 6px;border-radius:10px}\n"] }]
653
669
  }], ctorParameters: () => [] });
654
670
 
655
671
  class ChatWidgetModule {
@@ -673,7 +689,8 @@ class ChatWidgetModule {
673
689
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatWidgetModule, imports: [CommonModule,
674
690
  ChatLauncherComponent,
675
691
  ChatWindowComponent,
676
- AllChatsComponent] }); }
692
+ AllChatsComponent,
693
+ ChatWidgetNotificationComponent] }); }
677
694
  }
678
695
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ChatWidgetModule, decorators: [{
679
696
  type: NgModule,
@@ -698,5 +715,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
698
715
  * Generated bundle index. Do not edit.
699
716
  */
700
717
 
701
- export { AllChatsComponent, ChatLauncherComponent, ChatWidgetModule };
718
+ export { AllChatsComponent, ChatLauncherComponent, ChatWidgetModule, ChatWidgetNotificationComponent };
702
719
  //# sourceMappingURL=arthakosh-chat-widget.mjs.map