@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.
- package/esm2022/lib/chat-widget-notification/chat-widget-notification.component.mjs +8 -3
- package/esm2022/lib/chat-widget.module.mjs +3 -2
- package/esm2022/lib/chat-window/chat-window.component.mjs +1 -45
- package/esm2022/lib/core/services/chat.service.mjs +62 -4
- package/esm2022/public-api.mjs +2 -1
- package/fesm2022/arthakosh-chat-widget.mjs +159 -142
- package/fesm2022/arthakosh-chat-widget.mjs.map +1 -1
- package/lib/chat-window/chat-window.component.d.ts +0 -4
- package/lib/core/services/chat.service.d.ts +7 -1
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken,
|
|
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: [
|
|
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
|