@nyaruka/temba-components 0.91.5 → 0.92.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/demo/index.html +1 -1
- package/dist/temba-components.js +759 -1186
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +714 -0
- package/out-tsc/src/chat/Chat.js.map +1 -0
- package/out-tsc/src/completion/helpers.js +1 -29
- package/out-tsc/src/completion/helpers.js.map +1 -1
- package/out-tsc/src/compose/Compose.js +6 -2
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +518 -54
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/events.js +1 -998
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/lightbox/Lightbox.js +4 -0
- package/out-tsc/src/lightbox/Lightbox.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +0 -1
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/markdown.js +33 -0
- package/out-tsc/src/markdown.js.map +1 -0
- package/out-tsc/src/mediapicker/MediaPicker.js +6 -0
- package/out-tsc/src/mediapicker/MediaPicker.js.map +1 -1
- package/out-tsc/src/select/Select.js +6 -1
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/templates/TemplateEditor.js +18 -5
- package/out-tsc/src/templates/TemplateEditor.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +1 -1
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/thumbnail/Thumbnail.js +128 -81
- package/out-tsc/src/thumbnail/Thumbnail.js.map +1 -1
- package/out-tsc/src/utils/index.js +9 -11
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/src/webchat/WebChat.js +109 -358
- package/out-tsc/src/webchat/WebChat.js.map +1 -1
- package/out-tsc/src/webchat/index.js +17 -0
- package/out-tsc/src/webchat/index.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/temba-webchat.js +2 -0
- package/out-tsc/temba-webchat.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -0
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-lightbox.test.js +4 -4
- package/out-tsc/test/temba-lightbox.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
- package/screenshots/truth/contacts/compose-attachments-no-text-success.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-generic.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
- package/screenshots/truth/contacts/compose-text-and-attachments-success.png +0 -0
- package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
- package/screenshots/truth/contacts/compose-text-no-attachments-success.png +0 -0
- package/screenshots/truth/contacts/contact-active-default.png +0 -0
- package/screenshots/truth/contacts/contact-active-show-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-archived-hide-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-blocked-hide-chatbox.png +0 -0
- package/screenshots/truth/contacts/contact-stopped-hide-chatbox.png +0 -0
- package/screenshots/truth/lightbox/img-zoomed.png +0 -0
- package/screenshots/truth/lightbox/img.png +0 -0
- package/src/chat/Chat.ts +791 -0
- package/src/completion/helpers.ts +2 -40
- package/src/compose/Compose.ts +6 -2
- package/src/contacts/ContactChat.ts +609 -59
- package/src/contacts/events.ts +1 -1068
- package/src/interfaces.ts +1 -0
- package/src/lightbox/Lightbox.ts +5 -0
- package/src/list/TembaMenu.ts +0 -1
- package/src/markdown.ts +41 -0
- package/src/mediapicker/MediaPicker.ts +9 -1
- package/src/select/Select.ts +5 -1
- package/src/templates/TemplateEditor.ts +21 -5
- package/src/textinput/TextInput.ts +1 -1
- package/src/thumbnail/Thumbnail.ts +130 -81
- package/src/utils/index.ts +12 -13
- package/src/webchat/WebChat.ts +196 -413
- package/src/webchat/index.ts +23 -1
- package/static/css/temba-components.css +2 -0
- package/temba-modules.ts +2 -2
- package/temba-webchat.ts +2 -0
- package/test/temba-contact-chat.test.ts +1 -0
- package/test/temba-lightbox.test.ts +4 -4
- package/test-assets/contacts/history.json +1 -56
- package/out-tsc/src/contacts/ContactHistory.js +0 -691
- package/out-tsc/src/contacts/ContactHistory.js.map +0 -1
- package/out-tsc/test/temba-contact-history.test.js +0 -69
- package/out-tsc/test/temba-contact-history.test.js.map +0 -1
- package/src/contacts/ContactHistory.ts +0 -875
- package/test/temba-contact-history.test.ts +0 -107
|
@@ -4,30 +4,24 @@ import { LitElement, html, css } from 'lit';
|
|
|
4
4
|
import { property } from 'lit/decorators.js';
|
|
5
5
|
import { getCookie, setCookie } from '../utils';
|
|
6
6
|
import { DEFAULT_AVATAR } from './assets';
|
|
7
|
+
import { MessageType } from '../chat/Chat';
|
|
7
8
|
var ChatStatus;
|
|
8
9
|
(function (ChatStatus) {
|
|
9
10
|
ChatStatus["DISCONNECTED"] = "disconnected";
|
|
10
11
|
ChatStatus["CONNECTING"] = "connecting";
|
|
11
12
|
ChatStatus["CONNECTED"] = "connected";
|
|
12
13
|
})(ChatStatus || (ChatStatus = {}));
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
const VERBOSE_FORMAT = {
|
|
25
|
-
weekday: undefined,
|
|
26
|
-
year: undefined,
|
|
27
|
-
month: 'short',
|
|
28
|
-
day: 'numeric',
|
|
29
|
-
hour: 'numeric',
|
|
30
|
-
minute: '2-digit'
|
|
14
|
+
const sockToChat = function (msg) {
|
|
15
|
+
const type = msg.msg_in ? MessageType.MsgIn : MessageType.MsgOut;
|
|
16
|
+
const msgContent = msg.msg_in || msg.msg_out;
|
|
17
|
+
return {
|
|
18
|
+
id: msgContent.id,
|
|
19
|
+
type,
|
|
20
|
+
text: msgContent.text,
|
|
21
|
+
date: new Date(msgContent.time),
|
|
22
|
+
user: msgContent.user,
|
|
23
|
+
attachments: msgContent.attachments
|
|
24
|
+
};
|
|
31
25
|
};
|
|
32
26
|
export class WebChat extends LitElement {
|
|
33
27
|
static get styles() {
|
|
@@ -108,6 +102,11 @@ export class WebChat extends LitElement {
|
|
|
108
102
|
background: #fff;
|
|
109
103
|
}
|
|
110
104
|
|
|
105
|
+
.border {
|
|
106
|
+
border-top: 1px solid #e9e9e9;
|
|
107
|
+
margin: 0 1em;
|
|
108
|
+
}
|
|
109
|
+
|
|
111
110
|
.avatar {
|
|
112
111
|
margin-top: 0.6em;
|
|
113
112
|
margin-right: 0.6em;
|
|
@@ -180,6 +179,7 @@ export class WebChat extends LitElement {
|
|
|
180
179
|
}
|
|
181
180
|
|
|
182
181
|
.chat {
|
|
182
|
+
height: 40rem;
|
|
183
183
|
width: 28rem;
|
|
184
184
|
border-radius: var(--curvature);
|
|
185
185
|
overflow: hidden;
|
|
@@ -192,6 +192,9 @@ export class WebChat extends LitElement {
|
|
|
192
192
|
transform: scale(0.9);
|
|
193
193
|
pointer-events: none;
|
|
194
194
|
opacity: 0;
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: column;
|
|
197
|
+
background: #fff;
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
.chat.open {
|
|
@@ -201,61 +204,6 @@ export class WebChat extends LitElement {
|
|
|
201
204
|
pointer-events: initial;
|
|
202
205
|
}
|
|
203
206
|
|
|
204
|
-
.messages {
|
|
205
|
-
background: #fff;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.scroll {
|
|
209
|
-
height: 40rem;
|
|
210
|
-
max-height: 60vh;
|
|
211
|
-
overflow: auto;
|
|
212
|
-
-webkit-overflow-scrolling: touch;
|
|
213
|
-
overflow-scrolling: touch;
|
|
214
|
-
padding: 1em 1em 0 1em;
|
|
215
|
-
display: flex;
|
|
216
|
-
flex-direction: column-reverse;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.messages:before {
|
|
220
|
-
content: '';
|
|
221
|
-
background: /* Shadow TOP */ radial-gradient(
|
|
222
|
-
farthest-side at 50% 0,
|
|
223
|
-
rgba(0, 0, 0, 0.2),
|
|
224
|
-
rgba(0, 0, 0, 0)
|
|
225
|
-
)
|
|
226
|
-
center top;
|
|
227
|
-
height: 10px;
|
|
228
|
-
display: block;
|
|
229
|
-
position: absolute;
|
|
230
|
-
width: 28rem;
|
|
231
|
-
transition: opacity var(--toggle-speed) ease-out;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.messages:after {
|
|
235
|
-
content: '';
|
|
236
|
-
background: /* Shadow BOTTOM */ radial-gradient(
|
|
237
|
-
farthest-side at 50% 100%,
|
|
238
|
-
rgba(0, 0, 0, 0.2),
|
|
239
|
-
rgba(0, 0, 0, 0)
|
|
240
|
-
)
|
|
241
|
-
center bottom;
|
|
242
|
-
height: 10px;
|
|
243
|
-
display: block;
|
|
244
|
-
position: absolute;
|
|
245
|
-
margin-top: -10px;
|
|
246
|
-
width: 28rem;
|
|
247
|
-
margin-right: 5em;
|
|
248
|
-
transition: opacity var(--toggle-speed) ease-out;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.scroll-at-top .messages:before {
|
|
252
|
-
opacity: 0;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.scroll-at-bottom .messages:after {
|
|
256
|
-
opacity: 0;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
207
|
.input {
|
|
260
208
|
border: none;
|
|
261
209
|
flex-grow: 1;
|
|
@@ -337,20 +285,22 @@ export class WebChat extends LitElement {
|
|
|
337
285
|
this.status = ChatStatus.DISCONNECTED;
|
|
338
286
|
// is the chat widget open
|
|
339
287
|
this.open = false;
|
|
340
|
-
this.fetching = false;
|
|
341
288
|
this.hasPendingText = false;
|
|
342
|
-
this.hideTopScroll = true;
|
|
343
|
-
this.hideBottomScroll = true;
|
|
344
289
|
this.blockHistoryFetching = false;
|
|
345
|
-
this.msgMap = new Map();
|
|
346
290
|
this.newMessageCount = 0;
|
|
347
291
|
}
|
|
292
|
+
firstUpdated(changed) {
|
|
293
|
+
super.firstUpdated(changed);
|
|
294
|
+
this.chat = this.shadowRoot.querySelector('temba-chat');
|
|
295
|
+
const lightbox = document.createElement('temba-lightbox');
|
|
296
|
+
document.querySelector('body').appendChild(lightbox);
|
|
297
|
+
}
|
|
348
298
|
handleReconnect() {
|
|
349
299
|
this.openSocket();
|
|
350
300
|
}
|
|
351
|
-
sendSockMessage(
|
|
352
|
-
console.log('
|
|
353
|
-
this.sock.send(JSON.stringify(
|
|
301
|
+
sendSockMessage(cmd) {
|
|
302
|
+
console.log('out', cmd);
|
|
303
|
+
this.sock.send(JSON.stringify(cmd));
|
|
354
304
|
}
|
|
355
305
|
openSocket() {
|
|
356
306
|
if (this.status !== ChatStatus.DISCONNECTED) {
|
|
@@ -358,155 +308,89 @@ export class WebChat extends LitElement {
|
|
|
358
308
|
}
|
|
359
309
|
this.status = ChatStatus.CONNECTING;
|
|
360
310
|
const webChat = this;
|
|
361
|
-
let url = `wss://localhost.textit.com/connect/${this.channel}/`;
|
|
311
|
+
let url = `wss://localhost.textit.com/wc/connect/${this.channel}/`;
|
|
362
312
|
if (this.urn) {
|
|
363
313
|
url = `${url}?chat_id=${this.urn}`;
|
|
364
314
|
}
|
|
365
315
|
const sock = new WebSocket(url);
|
|
366
316
|
this.sock = sock;
|
|
367
|
-
this.sock.onclose = function (
|
|
368
|
-
console.log('Socket closed', event);
|
|
317
|
+
this.sock.onclose = function () {
|
|
369
318
|
webChat.status = ChatStatus.DISCONNECTED;
|
|
370
319
|
};
|
|
371
|
-
this.sock.onopen = function (
|
|
372
|
-
|
|
320
|
+
this.sock.onopen = function () {
|
|
321
|
+
webChat.beforeTime = new Date().toISOString();
|
|
373
322
|
webChat.status = ChatStatus.CONNECTED;
|
|
374
323
|
webChat.urn = getCookie('temba-chat-urn');
|
|
375
|
-
const
|
|
324
|
+
const cmd = { type: 'start_chat' };
|
|
376
325
|
if (webChat.urn) {
|
|
377
|
-
|
|
326
|
+
cmd.chat_id = webChat.urn;
|
|
378
327
|
}
|
|
379
|
-
webChat.sendSockMessage(
|
|
328
|
+
webChat.sendSockMessage(cmd);
|
|
380
329
|
};
|
|
381
330
|
this.sock.onmessage = function (event) {
|
|
382
331
|
webChat.status = ChatStatus.CONNECTED;
|
|
383
332
|
const msg = JSON.parse(event.data);
|
|
384
|
-
console.log('
|
|
333
|
+
console.log('in', msg);
|
|
385
334
|
if (msg.type === 'chat_started') {
|
|
386
|
-
|
|
335
|
+
const response = msg;
|
|
336
|
+
if (webChat.urn !== response.chat_id) {
|
|
387
337
|
webChat.messageGroups = [];
|
|
388
338
|
}
|
|
389
|
-
webChat.urn =
|
|
390
|
-
setCookie('temba-chat-urn',
|
|
339
|
+
webChat.urn = response.chat_id;
|
|
340
|
+
setCookie('temba-chat-urn', response.chat_id);
|
|
391
341
|
webChat.requestUpdate('messageGroups');
|
|
392
342
|
}
|
|
393
343
|
else if (msg.type === 'chat_resumed') {
|
|
394
|
-
|
|
395
|
-
webChat.urn =
|
|
344
|
+
const response = msg;
|
|
345
|
+
webChat.urn = response.chat_id;
|
|
396
346
|
webChat.fetchPreviousMessages();
|
|
397
347
|
}
|
|
398
|
-
else if (msg.type === '
|
|
399
|
-
|
|
400
|
-
webChat.
|
|
348
|
+
else if (msg.type === 'chat_out') {
|
|
349
|
+
const response = msg;
|
|
350
|
+
webChat.chat.addMessages([sockToChat(response)], null, true);
|
|
351
|
+
// ack receipt
|
|
352
|
+
const ack = { type: 'ack_chat', msg_id: response.msg_out.id };
|
|
353
|
+
webChat.sendSockMessage(ack);
|
|
401
354
|
}
|
|
402
355
|
else if (msg.type === 'history') {
|
|
403
356
|
webChat.handleHistoryResponse(msg);
|
|
404
357
|
}
|
|
405
358
|
};
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
if (msg1 && msg2) {
|
|
410
|
-
return (msg1.origin === msg2.origin &&
|
|
411
|
-
((_a = msg1.user) === null || _a === void 0 ? void 0 : _a.name) === ((_b = msg2.user) === null || _b === void 0 ? void 0 : _b.name) &&
|
|
412
|
-
Math.abs(msg1.timeAsDate.getTime() - msg2.timeAsDate.getTime()) <
|
|
413
|
-
BATCH_TIME_WINDOW);
|
|
414
|
-
}
|
|
415
|
-
return false;
|
|
416
|
-
}
|
|
417
|
-
insertGroups(newGroups, append = false) {
|
|
418
|
-
newGroups.reverse();
|
|
419
|
-
for (const newGroup of newGroups) {
|
|
420
|
-
// see if our new group belongs to the most recent group
|
|
421
|
-
const group = this.messageGroups[append ? 0 : this.messageGroups.length - 1];
|
|
422
|
-
if (group) {
|
|
423
|
-
const lastMsgId = group[group.length - 1];
|
|
424
|
-
const lastMsg = this.msgMap.get(lastMsgId);
|
|
425
|
-
const newMsg = this.msgMap.get(newGroup[0]);
|
|
426
|
-
// if our message belongs to the previous group, in we go
|
|
427
|
-
if (this.isSameGroup(lastMsg, newMsg)) {
|
|
428
|
-
group.push(...newGroup);
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
// otherwise, just add our entire group as a new one
|
|
432
|
-
if (append) {
|
|
433
|
-
this.messageGroups.splice(0, 0, newGroup);
|
|
434
|
-
}
|
|
435
|
-
else {
|
|
436
|
-
this.messageGroups.push(newGroup);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
if (append) {
|
|
442
|
-
this.messageGroups.splice(0, 0, newGroup);
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
this.messageGroups.push(newGroup);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
this.requestUpdate('messageGroups');
|
|
450
|
-
}
|
|
451
|
-
groupMessages(msgIds) {
|
|
452
|
-
// group our messages by origin and user
|
|
453
|
-
const groups = [];
|
|
454
|
-
let lastGroup = [];
|
|
455
|
-
let lastMsg = null;
|
|
456
|
-
for (const msgId of msgIds) {
|
|
457
|
-
const msg = this.msgMap.get(msgId);
|
|
458
|
-
if (!this.isSameGroup(msg, lastMsg)) {
|
|
459
|
-
lastGroup = [];
|
|
460
|
-
groups.push(lastGroup);
|
|
461
|
-
}
|
|
462
|
-
lastGroup.push(msgId);
|
|
463
|
-
lastMsg = msg;
|
|
464
|
-
}
|
|
465
|
-
return groups;
|
|
359
|
+
this.sock.onerror = function () {
|
|
360
|
+
webChat.status = ChatStatus.DISCONNECTED;
|
|
361
|
+
};
|
|
466
362
|
}
|
|
467
363
|
fetchPreviousMessages() {
|
|
468
364
|
if (!this.blockHistoryFetching) {
|
|
365
|
+
this.fetchRequested = new Date();
|
|
469
366
|
this.blockHistoryFetching = true;
|
|
470
|
-
this.fetching = true;
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
367
|
+
this.chat.fetching = true;
|
|
368
|
+
const cmd = {
|
|
369
|
+
type: 'get_history',
|
|
370
|
+
before: this.beforeTime
|
|
371
|
+
};
|
|
475
372
|
this.fetchRequested = new Date();
|
|
476
|
-
this.sendSockMessage(
|
|
373
|
+
this.sendSockMessage(cmd);
|
|
477
374
|
}
|
|
478
375
|
}
|
|
479
|
-
handleHistoryResponse(
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const newMessages = [];
|
|
487
|
-
for (const m of msgs) {
|
|
488
|
-
if (this.addMessage(m)) {
|
|
489
|
-
newMessages.push(m.msg_id);
|
|
490
|
-
}
|
|
376
|
+
handleHistoryResponse(response) {
|
|
377
|
+
const messages = response.history.reverse();
|
|
378
|
+
if (messages.length > 0) {
|
|
379
|
+
const oldestMessage = messages[0];
|
|
380
|
+
if (oldestMessage['msg_in']) {
|
|
381
|
+
const msgIn = oldestMessage.msg_in;
|
|
382
|
+
this.beforeTime = msgIn.time;
|
|
491
383
|
}
|
|
492
|
-
if (
|
|
493
|
-
|
|
384
|
+
else if (oldestMessage['msg_out']) {
|
|
385
|
+
const msgOut = oldestMessage.msg_out;
|
|
386
|
+
this.beforeTime = msgOut.time;
|
|
494
387
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
window.setTimeout(() => {
|
|
499
|
-
ele.scrollTop = prevTop;
|
|
500
|
-
this.blockHistoryFetching = false;
|
|
501
|
-
}, 100);
|
|
502
|
-
},
|
|
503
|
-
// if it's the first load don't wait, otherwise wait a minimum amount of time
|
|
504
|
-
this.messageGroups.length === 0
|
|
505
|
-
? 0
|
|
506
|
-
: Math.max(0, MIN_FETCH_TIME - elapsed));
|
|
388
|
+
}
|
|
389
|
+
// convert messages to chat messages
|
|
390
|
+
this.chat.addMessages(messages.map(sockToChat), this.fetchRequested);
|
|
507
391
|
}
|
|
508
|
-
|
|
509
|
-
|
|
392
|
+
fetchComplete() {
|
|
393
|
+
this.blockHistoryFetching = false;
|
|
510
394
|
}
|
|
511
395
|
focusInput() {
|
|
512
396
|
const input = this.shadowRoot.querySelector('.input');
|
|
@@ -517,11 +401,6 @@ export class WebChat extends LitElement {
|
|
|
517
401
|
updated(changed) {
|
|
518
402
|
super.updated(changed);
|
|
519
403
|
if (this.open && changed.has('open') && changed.get('open') !== undefined) {
|
|
520
|
-
const scroll = this.shadowRoot.querySelector('.scroll');
|
|
521
|
-
const hasScroll = scroll.scrollHeight > scroll.clientHeight;
|
|
522
|
-
this.hideBottomScroll = true;
|
|
523
|
-
this.hideTopScroll = !hasScroll;
|
|
524
|
-
this.scrollToBottom();
|
|
525
404
|
if (this.status === ChatStatus.DISCONNECTED) {
|
|
526
405
|
this.openSocket();
|
|
527
406
|
}
|
|
@@ -532,22 +411,6 @@ export class WebChat extends LitElement {
|
|
|
532
411
|
}
|
|
533
412
|
}
|
|
534
413
|
}
|
|
535
|
-
addMessage(msg) {
|
|
536
|
-
var _a;
|
|
537
|
-
if (msg.time && !msg.timeAsDate) {
|
|
538
|
-
msg.timeAsDate = new Date(msg.time);
|
|
539
|
-
}
|
|
540
|
-
if (!this.oldestMessageDate ||
|
|
541
|
-
msg.timeAsDate.getTime() < this.oldestMessageDate.getTime()) {
|
|
542
|
-
this.oldestMessageDate = msg.timeAsDate;
|
|
543
|
-
}
|
|
544
|
-
const isNew = !this.msgMap.has(msg.msg_id);
|
|
545
|
-
this.msgMap.set(msg.msg_id, msg);
|
|
546
|
-
if ((_a = msg.user) === null || _a === void 0 ? void 0 : _a.avatar) {
|
|
547
|
-
this.activeUserAvatar = msg.user.avatar;
|
|
548
|
-
}
|
|
549
|
-
return isNew;
|
|
550
|
-
}
|
|
551
414
|
openChat() {
|
|
552
415
|
this.open = true;
|
|
553
416
|
}
|
|
@@ -563,109 +426,17 @@ export class WebChat extends LitElement {
|
|
|
563
426
|
const text = input.value;
|
|
564
427
|
input.value = '';
|
|
565
428
|
const msg = {
|
|
566
|
-
msg_id: `pending-${this.newMessageCount++}`,
|
|
429
|
+
// msg_id: `pending-${this.newMessageCount++}`,
|
|
567
430
|
type: 'send_msg',
|
|
568
|
-
text: text
|
|
569
|
-
time: new Date().toISOString()
|
|
431
|
+
text: text
|
|
432
|
+
// time: new Date().toISOString()
|
|
570
433
|
};
|
|
571
|
-
this.addMessage(msg);
|
|
572
|
-
this.insertGroups(this.groupMessages([msg.msg_id]), true);
|
|
573
434
|
this.sendSockMessage(msg);
|
|
435
|
+
const date = new Date();
|
|
436
|
+
this.chat.addMessages([{ type: MessageType.MsgIn, text, date }], date, true);
|
|
574
437
|
this.hasPendingText = input.value.length > 0;
|
|
575
438
|
}
|
|
576
439
|
}
|
|
577
|
-
scrollToBottom() {
|
|
578
|
-
const scroll = this.shadowRoot.querySelector('.scroll');
|
|
579
|
-
if (scroll) {
|
|
580
|
-
scroll.scrollTop = scroll.scrollHeight;
|
|
581
|
-
this.hideBottomScroll = true;
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
renderMessageGroup(msgIds, idx, groups) {
|
|
585
|
-
var _a, _b;
|
|
586
|
-
const today = new Date();
|
|
587
|
-
let prevMsg;
|
|
588
|
-
if (idx > 0) {
|
|
589
|
-
const lastGroup = groups[idx - 1];
|
|
590
|
-
if (lastGroup && lastGroup.length > 0) {
|
|
591
|
-
prevMsg = this.msgMap.get(lastGroup[0]);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
const currentMsg = this.msgMap.get(msgIds[msgIds.length - 1]);
|
|
595
|
-
let timeDisplay = null;
|
|
596
|
-
if (prevMsg &&
|
|
597
|
-
!this.isSameGroup(prevMsg, currentMsg) &&
|
|
598
|
-
prevMsg.timeAsDate.getTime() - currentMsg.timeAsDate.getTime() >
|
|
599
|
-
BATCH_TIME_WINDOW) {
|
|
600
|
-
const showDay = !prevMsg ||
|
|
601
|
-
prevMsg.timeAsDate.getDate() !== currentMsg.timeAsDate.getDate();
|
|
602
|
-
if (showDay) {
|
|
603
|
-
timeDisplay = html `<div class="time">
|
|
604
|
-
${prevMsg.timeAsDate.toLocaleDateString(undefined, DAY_FORMAT)}
|
|
605
|
-
</div>`;
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
608
|
-
if (prevMsg.timeAsDate.getDate() !== today.getDate()) {
|
|
609
|
-
timeDisplay = html `<div class="time">
|
|
610
|
-
${prevMsg.timeAsDate.toLocaleTimeString(undefined, VERBOSE_FORMAT)}
|
|
611
|
-
</div>`;
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
timeDisplay = html `<div class="time">
|
|
615
|
-
${prevMsg.timeAsDate.toLocaleTimeString(undefined, TIME_FORMAT)}
|
|
616
|
-
</div>`;
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
const blockTime = new Date(this.msgMap.get(msgIds[msgIds.length - 1]).time);
|
|
621
|
-
const message = this.msgMap.get(msgIds[0]);
|
|
622
|
-
const incoming = !message.origin;
|
|
623
|
-
const avatar = (_a = message.user) === null || _a === void 0 ? void 0 : _a.avatar;
|
|
624
|
-
const name = (_b = message.user) === null || _b === void 0 ? void 0 : _b.name;
|
|
625
|
-
return html ` <div
|
|
626
|
-
class="block ${incoming ? 'incoming' : 'outgoing'} ${idx === 0
|
|
627
|
-
? 'first'
|
|
628
|
-
: ''}"
|
|
629
|
-
title="${blockTime.toLocaleTimeString(undefined, VERBOSE_FORMAT)}"
|
|
630
|
-
>
|
|
631
|
-
<div class="row">
|
|
632
|
-
${!incoming
|
|
633
|
-
? html `
|
|
634
|
-
<div
|
|
635
|
-
class="avatar"
|
|
636
|
-
style="background: center / contain no-repeat url(${avatar ||
|
|
637
|
-
DEFAULT_AVATAR})"
|
|
638
|
-
></div>
|
|
639
|
-
`
|
|
640
|
-
: null}
|
|
641
|
-
|
|
642
|
-
<div class="bubble">
|
|
643
|
-
${!incoming ? html `<div class="name">${name}</div>` : null}
|
|
644
|
-
${msgIds.map((msgId) => html `<div class="message">${this.msgMap.get(msgId).text}</div>
|
|
645
|
-
<!--div style="font-size:10px">
|
|
646
|
-
${this.msgMap
|
|
647
|
-
.get(msgId)
|
|
648
|
-
.timeAsDate.toLocaleDateString(undefined, VERBOSE_FORMAT)}
|
|
649
|
-
</div-->`)}
|
|
650
|
-
</div>
|
|
651
|
-
</div>
|
|
652
|
-
${timeDisplay}
|
|
653
|
-
</div>`;
|
|
654
|
-
}
|
|
655
|
-
handleScroll(event) {
|
|
656
|
-
const ele = event.target;
|
|
657
|
-
const top = ele.scrollHeight - ele.clientHeight;
|
|
658
|
-
const scroll = Math.round(top + ele.scrollTop);
|
|
659
|
-
const scrollPct = scroll / top;
|
|
660
|
-
this.hideTopScroll = scrollPct <= 0.01;
|
|
661
|
-
this.hideBottomScroll = scrollPct >= 0.99;
|
|
662
|
-
if (this.blockHistoryFetching) {
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
if (scrollPct < SCROLL_FETCH_BUFFER) {
|
|
666
|
-
this.fetchPreviousMessages();
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
440
|
handleClickInputPanel(event) {
|
|
670
441
|
event.preventDefault();
|
|
671
442
|
event.stopPropagation();
|
|
@@ -677,13 +448,7 @@ export class WebChat extends LitElement {
|
|
|
677
448
|
}
|
|
678
449
|
render() {
|
|
679
450
|
return html `
|
|
680
|
-
<div
|
|
681
|
-
class="chat ${this.status} ${this.hideTopScroll
|
|
682
|
-
? 'scroll-at-top'
|
|
683
|
-
: ''} ${this.hideBottomScroll ? 'scroll-at-bottom' : ''} ${this.open
|
|
684
|
-
? 'open'
|
|
685
|
-
: ''}"
|
|
686
|
-
>
|
|
451
|
+
<div class="chat ${this.status} ${this.open ? 'open' : ''}">
|
|
687
452
|
<div class="header">
|
|
688
453
|
<slot name="header">${this.urn ? this.urn : 'Chat'}</slot>
|
|
689
454
|
<temba-icon
|
|
@@ -693,17 +458,11 @@ export class WebChat extends LitElement {
|
|
|
693
458
|
@click=${this.toggleChat}
|
|
694
459
|
></temba-icon>
|
|
695
460
|
</div>
|
|
696
|
-
<div class="messages">
|
|
697
|
-
<div class="scroll" @scroll=${this.handleScroll}>
|
|
698
|
-
${this.messageGroups
|
|
699
|
-
? this.messageGroups.map((msgGroup, idx, groups) => html `${this.renderMessageGroup(msgGroup, idx, groups)}`)
|
|
700
|
-
: null}
|
|
701
461
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
</div>
|
|
462
|
+
<temba-chat
|
|
463
|
+
@temba-scroll-threshold=${this.fetchPreviousMessages}
|
|
464
|
+
@temba-fetch-complete=${this.fetchComplete}
|
|
465
|
+
></temba-chat>
|
|
707
466
|
|
|
708
467
|
${this.status === ChatStatus.DISCONNECTED
|
|
709
468
|
? html `<div class="notice">
|
|
@@ -721,28 +480,29 @@ export class WebChat extends LitElement {
|
|
|
721
480
|
</div>`
|
|
722
481
|
: null}
|
|
723
482
|
${this.status === ChatStatus.CONNECTED
|
|
724
|
-
? html ` <div
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
483
|
+
? html ` <div class="border"></div>
|
|
484
|
+
<div
|
|
485
|
+
class="row input-panel ${this.hasPendingText ? 'pending' : ''}"
|
|
486
|
+
@click=${this.handleClickInputPanel}
|
|
487
|
+
>
|
|
488
|
+
<input
|
|
489
|
+
class="input ${this.status === ChatStatus.CONNECTED
|
|
730
490
|
? 'active'
|
|
731
491
|
: 'inactive'}"
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
492
|
+
type="text"
|
|
493
|
+
placeholder="Message.."
|
|
494
|
+
?disabled=${this.status !== ChatStatus.CONNECTED}
|
|
495
|
+
@keydown=${this.handleKeyUp}
|
|
496
|
+
/>
|
|
497
|
+
<temba-icon
|
|
498
|
+
tabindex="1"
|
|
499
|
+
class="send-icon"
|
|
500
|
+
name="send"
|
|
501
|
+
size="1"
|
|
502
|
+
clickable
|
|
503
|
+
@click=${this.sendPendingMessage}
|
|
504
|
+
></temba-icon>
|
|
505
|
+
</div>`
|
|
746
506
|
: null}
|
|
747
507
|
</div>
|
|
748
508
|
|
|
@@ -771,25 +531,16 @@ __decorate([
|
|
|
771
531
|
__decorate([
|
|
772
532
|
property({ type: Boolean })
|
|
773
533
|
], WebChat.prototype, "open", void 0);
|
|
774
|
-
__decorate([
|
|
775
|
-
property({ type: Boolean })
|
|
776
|
-
], WebChat.prototype, "fetching", void 0);
|
|
777
534
|
__decorate([
|
|
778
535
|
property({ type: Boolean })
|
|
779
536
|
], WebChat.prototype, "hasPendingText", void 0);
|
|
780
|
-
__decorate([
|
|
781
|
-
property({ type: Boolean, attribute: false })
|
|
782
|
-
], WebChat.prototype, "hideTopScroll", void 0);
|
|
783
|
-
__decorate([
|
|
784
|
-
property({ type: Boolean, attribute: false })
|
|
785
|
-
], WebChat.prototype, "hideBottomScroll", void 0);
|
|
786
|
-
__decorate([
|
|
787
|
-
property({ type: Boolean, attribute: false })
|
|
788
|
-
], WebChat.prototype, "blockHistoryFetching", void 0);
|
|
789
537
|
__decorate([
|
|
790
538
|
property({ type: String })
|
|
791
539
|
], WebChat.prototype, "host", void 0);
|
|
792
540
|
__decorate([
|
|
793
541
|
property({ type: String })
|
|
794
542
|
], WebChat.prototype, "activeUserAvatar", void 0);
|
|
543
|
+
__decorate([
|
|
544
|
+
property({ type: Boolean, attribute: false })
|
|
545
|
+
], WebChat.prototype, "blockHistoryFetching", void 0);
|
|
795
546
|
//# sourceMappingURL=WebChat.js.map
|