@hellotext/hellotext 2.1.2 → 2.1.4
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/dist/hellotext.js +1 -1
- package/lib/api/forms.cjs +2 -1
- package/lib/api/forms.js +2 -1
- package/lib/api/webchat/messages.cjs +4 -3
- package/lib/api/webchat/messages.js +4 -2
- package/lib/api/webchats.cjs +2 -0
- package/lib/api/webchats.js +3 -1
- package/lib/builders/logo_builder.cjs +1 -1
- package/lib/builders/logo_builder.js +1 -1
- package/lib/channels/application_channel.cjs +9 -6
- package/lib/channels/application_channel.js +9 -6
- package/lib/channels/webchat_channel.cjs +42 -17
- package/lib/channels/webchat_channel.js +42 -17
- package/lib/controllers/webchat/emoji_picker_controller.cjs +6 -6
- package/lib/controllers/webchat/emoji_picker_controller.js +5 -14
- package/lib/controllers/webchat_controller.cjs +174 -47
- package/lib/controllers/webchat_controller.js +175 -48
- package/lib/core/configuration/locale.cjs +87 -0
- package/lib/core/configuration/locale.js +81 -0
- package/lib/core/configuration.cjs +11 -0
- package/lib/core/configuration.js +11 -0
- package/lib/core/index.cjs +15 -1
- package/lib/core/index.js +4 -2
- package/lib/locales/en.cjs +1 -1
- package/lib/locales/en.js +1 -1
- package/lib/locales/es.cjs +1 -1
- package/lib/locales/es.js +1 -1
- package/lib/models/business.cjs +11 -0
- package/lib/models/business.js +11 -0
- package/lib/models/form_collection.cjs +1 -0
- package/lib/models/form_collection.js +2 -1
- package/lib/models/index.cjs +4 -4
- package/lib/models/index.js +4 -4
- package/lib/models/query.cjs +1 -2
- package/lib/models/query.js +1 -2
- package/lib/models/session.cjs +1 -1
- package/lib/models/session.js +1 -1
- package/package.json +2 -1
- package/src/api/forms.js +3 -1
- package/src/api/webchat/messages.js +8 -6
- package/src/api/webchats.js +3 -1
- package/src/builders/logo_builder.js +1 -1
- package/src/channels/application_channel.js +12 -9
- package/src/channels/webchat_channel.js +33 -19
- package/src/controllers/webchat/emoji_picker_controller.js +9 -15
- package/src/controllers/webchat_controller.js +164 -43
- package/src/core/configuration/locale.js +50 -0
- package/src/core/configuration.js +11 -0
- package/src/core/index.js +3 -1
- package/src/locales/en.js +4 -4
- package/src/locales/es.js +4 -4
- package/src/models/business.js +12 -0
- package/src/models/form_collection.js +2 -1
- package/src/models/index.js +3 -3
- package/src/models/query.js +1 -3
- package/src/models/session.js +1 -1
|
@@ -9,6 +9,7 @@ var _stimulus = require("@hotwired/stimulus");
|
|
|
9
9
|
var _messages = _interopRequireDefault(require("../api/webchat/messages"));
|
|
10
10
|
var _webchat_channel = _interopRequireDefault(require("../channels/webchat_channel"));
|
|
11
11
|
var _hellotext = _interopRequireDefault(require("../hellotext"));
|
|
12
|
+
var _core = require("../core");
|
|
12
13
|
var _webchat = require("../core/configuration/webchat");
|
|
13
14
|
var _logo_builder = require("../builders/logo_builder");
|
|
14
15
|
var _usePopover = require("./mixins/usePopover");
|
|
@@ -41,9 +42,8 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
41
42
|
this.webChatChannel = new _webchat_channel.default(this.idValue, _hellotext.default.session, this.conversationIdValue);
|
|
42
43
|
this.files = [];
|
|
43
44
|
this.onMessageReceived = this.onMessageReceived.bind(this);
|
|
44
|
-
this.onConversationAssignment = this.onConversationAssignment.bind(this);
|
|
45
|
-
this.onAgentOnline = this.onAgentOnline.bind(this);
|
|
46
45
|
this.onMessageReaction = this.onMessageReaction.bind(this);
|
|
46
|
+
this.onTypingStart = this.onTypingStart.bind(this);
|
|
47
47
|
this.onScroll = this.onScroll.bind(this);
|
|
48
48
|
this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
|
|
49
49
|
this.broadcastChannel = new BroadcastChannel(`hellotext--webchat--${this.idValue}`);
|
|
@@ -60,14 +60,13 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
60
60
|
popover: this.popoverTarget
|
|
61
61
|
});
|
|
62
62
|
this.webChatChannel.onMessage(this.onMessageReceived);
|
|
63
|
-
this.webChatChannel.
|
|
64
|
-
this.webChatChannel.onAgentOnline(this.onAgentOnline);
|
|
63
|
+
this.webChatChannel.onTypingStart(this.onTypingStart);
|
|
65
64
|
this.webChatChannel.onReaction(this.onMessageReaction);
|
|
66
65
|
this.messagesContainerTarget.addEventListener('scroll', this.onScroll);
|
|
67
66
|
if (!_hellotext.default.business.features.white_label) {
|
|
68
67
|
this.toolbarTarget.appendChild(_logo_builder.LogoBuilder.build());
|
|
69
68
|
}
|
|
70
|
-
if (
|
|
69
|
+
if (this.shouldOpenOnMount) {
|
|
71
70
|
this.openValue = true;
|
|
72
71
|
}
|
|
73
72
|
_hellotext.default.eventEmitter.dispatch('webchat:mounted');
|
|
@@ -79,10 +78,85 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
79
78
|
value: function disconnect() {
|
|
80
79
|
this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
|
|
81
80
|
this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
|
|
81
|
+
|
|
82
|
+
// Clean up typing indicator timeouts
|
|
83
|
+
this.clearTypingIndicator();
|
|
82
84
|
this.broadcastChannel.close();
|
|
83
85
|
this.floatingUICleanup();
|
|
84
86
|
_get(_getPrototypeOf(_default.prototype), "disconnect", this).call(this);
|
|
85
87
|
}
|
|
88
|
+
}, {
|
|
89
|
+
key: "onTypingStart",
|
|
90
|
+
value: function onTypingStart() {
|
|
91
|
+
if (this.typingIndicatorVisible) {
|
|
92
|
+
return this.resetTypingIndicatorTimer();
|
|
93
|
+
}
|
|
94
|
+
this.showTypingIndicator();
|
|
95
|
+
}
|
|
96
|
+
}, {
|
|
97
|
+
key: "showOptimisticTypingIndicator",
|
|
98
|
+
value: function showOptimisticTypingIndicator() {
|
|
99
|
+
if (this.typingIndicatorVisible) return;
|
|
100
|
+
this.showTypingIndicator();
|
|
101
|
+
}
|
|
102
|
+
}, {
|
|
103
|
+
key: "showTypingIndicator",
|
|
104
|
+
value: function showTypingIndicator() {
|
|
105
|
+
this.clearTypingIndicator();
|
|
106
|
+
this.typingIndicatorVisible = true;
|
|
107
|
+
const indicator = this.typingIndicatorTemplateTarget.cloneNode(true);
|
|
108
|
+
indicator.setAttribute('data-hellotext--webchat-target', 'typingIndicator');
|
|
109
|
+
indicator.style.display = 'flex';
|
|
110
|
+
this.messagesContainerTarget.appendChild(indicator);
|
|
111
|
+
requestAnimationFrame(() => {
|
|
112
|
+
this.messagesContainerTarget.scroll({
|
|
113
|
+
top: this.messagesContainerTarget.scrollHeight,
|
|
114
|
+
behavior: 'instant'
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
const timeout = this.typingIndicatorKeepAliveValue;
|
|
118
|
+
this.incomingTypingIndicatorTimeout = setTimeout(() => {
|
|
119
|
+
this.clearTypingIndicator();
|
|
120
|
+
}, timeout);
|
|
121
|
+
}
|
|
122
|
+
}, {
|
|
123
|
+
key: "resetTypingIndicatorTimer",
|
|
124
|
+
value: function resetTypingIndicatorTimer() {
|
|
125
|
+
if (!this.typingIndicatorVisible) return;
|
|
126
|
+
|
|
127
|
+
// Clear existing timeout
|
|
128
|
+
clearTimeout(this.incomingTypingIndicatorTimeout);
|
|
129
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
130
|
+
|
|
131
|
+
// Use unified timeout for all typing indicators
|
|
132
|
+
const timeout = this.typingIndicatorKeepAliveValue;
|
|
133
|
+
this.incomingTypingIndicatorTimeout = setTimeout(() => {
|
|
134
|
+
this.clearTypingIndicator();
|
|
135
|
+
}, timeout);
|
|
136
|
+
}
|
|
137
|
+
}, {
|
|
138
|
+
key: "clearTypingIndicator",
|
|
139
|
+
value: function clearTypingIndicator() {
|
|
140
|
+
if (this.hasTypingIndicatorTarget) {
|
|
141
|
+
this.typingIndicatorTarget.remove();
|
|
142
|
+
}
|
|
143
|
+
this.typingIndicatorVisible = false;
|
|
144
|
+
clearTimeout(this.incomingTypingIndicatorTimeout);
|
|
145
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
146
|
+
}
|
|
147
|
+
}, {
|
|
148
|
+
key: "onMessageInputChange",
|
|
149
|
+
value: function onMessageInputChange() {
|
|
150
|
+
this.resizeInput();
|
|
151
|
+
clearTimeout(this.typingIndicatorTimeout);
|
|
152
|
+
if (!this.hasSentTypingIndicator) {
|
|
153
|
+
this.webChatChannel.startTypingIndicator();
|
|
154
|
+
this.hasSentTypingIndicator = true;
|
|
155
|
+
}
|
|
156
|
+
this.typingIndicatorTimeout = setTimeout(() => {
|
|
157
|
+
this.hasSentTypingIndicator = false;
|
|
158
|
+
}, 3000);
|
|
159
|
+
}
|
|
86
160
|
}, {
|
|
87
161
|
key: "onOutboundMessageSent",
|
|
88
162
|
value: function onOutboundMessageSent(event) {
|
|
@@ -92,7 +166,13 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
92
166
|
const callbacks = {
|
|
93
167
|
'message:sent': data => {
|
|
94
168
|
const element = new DOMParser().parseFromString(data.element, 'text/html').body.firstElementChild;
|
|
95
|
-
|
|
169
|
+
|
|
170
|
+
// Insert message before typing indicator if one exists
|
|
171
|
+
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
172
|
+
this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
|
|
173
|
+
} else {
|
|
174
|
+
this.messagesContainerTarget.appendChild(element);
|
|
175
|
+
}
|
|
96
176
|
element.scrollIntoView({
|
|
97
177
|
behavior: 'instant'
|
|
98
178
|
});
|
|
@@ -164,10 +244,20 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
164
244
|
this.openValue = false;
|
|
165
245
|
}
|
|
166
246
|
}
|
|
247
|
+
}, {
|
|
248
|
+
key: "closePopover",
|
|
249
|
+
value: function closePopover() {
|
|
250
|
+
this.popoverTarget.classList.add(...this.fadeOutClasses);
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
this.openValue = false;
|
|
253
|
+
}, 250);
|
|
254
|
+
}
|
|
167
255
|
}, {
|
|
168
256
|
key: "onPopoverOpened",
|
|
169
257
|
value: function onPopoverOpened() {
|
|
170
|
-
this.
|
|
258
|
+
if (!this.onMobile) {
|
|
259
|
+
this.inputTarget.focus();
|
|
260
|
+
}
|
|
171
261
|
if (!this.scrolled) {
|
|
172
262
|
requestAnimationFrame(() => {
|
|
173
263
|
this.messagesContainerTarget.scroll({
|
|
@@ -188,9 +278,6 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
188
278
|
key: "onPopoverClosed",
|
|
189
279
|
value: function onPopoverClosed() {
|
|
190
280
|
_hellotext.default.eventEmitter.dispatch('webchat:closed');
|
|
191
|
-
setTimeout(() => {
|
|
192
|
-
this.inputTarget.value = '';
|
|
193
|
-
});
|
|
194
281
|
localStorage.setItem(`hellotext--webchat--${this.idValue}`, 'closed');
|
|
195
282
|
}
|
|
196
283
|
}, {
|
|
@@ -221,6 +308,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
221
308
|
key: "onMessageReceived",
|
|
222
309
|
value: function onMessageReceived(message) {
|
|
223
310
|
const {
|
|
311
|
+
id,
|
|
224
312
|
body,
|
|
225
313
|
attachments
|
|
226
314
|
} = message;
|
|
@@ -238,6 +326,11 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
238
326
|
element.querySelector('[data-attachment-container]').appendChild(image);
|
|
239
327
|
});
|
|
240
328
|
}
|
|
329
|
+
|
|
330
|
+
// Clear any typing indicator when message is received
|
|
331
|
+
if (this.typingIndicatorVisible) {
|
|
332
|
+
this.clearTypingIndicator();
|
|
333
|
+
}
|
|
241
334
|
this.messagesContainerTarget.appendChild(element);
|
|
242
335
|
_hellotext.default.eventEmitter.dispatch('webchat:message:received', {
|
|
243
336
|
...message,
|
|
@@ -246,40 +339,39 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
246
339
|
element.scrollIntoView({
|
|
247
340
|
behavior: 'smooth'
|
|
248
341
|
});
|
|
249
|
-
this.
|
|
250
|
-
|
|
342
|
+
if (this.openValue) {
|
|
343
|
+
this.messagesAPI.markAsSeen(id);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
251
346
|
this.unreadCounterTarget.style.display = 'flex';
|
|
252
347
|
const unreadCount = (parseInt(this.unreadCounterTarget.innerText) || 0) + 1;
|
|
253
348
|
this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
|
|
254
349
|
}
|
|
255
350
|
}, {
|
|
256
|
-
key: "
|
|
257
|
-
value: function
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}, {
|
|
269
|
-
key: "onAgentOnline",
|
|
270
|
-
value: function onAgentOnline() {
|
|
271
|
-
this.onlineStatusTarget.style.display = 'flex';
|
|
272
|
-
this.setOfflineTimeout();
|
|
351
|
+
key: "resizeInput",
|
|
352
|
+
value: function resizeInput() {
|
|
353
|
+
const maxHeight = 96;
|
|
354
|
+
|
|
355
|
+
// Temporarily reset height to its natural content size
|
|
356
|
+
this.inputTarget.style.height = 'auto';
|
|
357
|
+
|
|
358
|
+
// Set the height to the scrollHeight, which is the minimum height
|
|
359
|
+
// the element needs to fit its content without a scrollbar.
|
|
360
|
+
const scrollHeight = this.inputTarget.scrollHeight;
|
|
361
|
+
this.inputTarget.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
|
|
273
362
|
}
|
|
274
363
|
}, {
|
|
275
364
|
key: "sendMessage",
|
|
276
|
-
value: async function sendMessage() {
|
|
365
|
+
value: async function sendMessage(e) {
|
|
277
366
|
const formData = new FormData();
|
|
278
367
|
const message = {
|
|
279
368
|
body: this.inputTarget.value,
|
|
280
369
|
attachments: this.files
|
|
281
370
|
};
|
|
282
371
|
if (this.inputTarget.value.trim().length === 0 && this.files.length === 0) {
|
|
372
|
+
if (e && e.target) {
|
|
373
|
+
e.preventDefault();
|
|
374
|
+
}
|
|
283
375
|
return;
|
|
284
376
|
}
|
|
285
377
|
if (this.inputTarget.value.trim().length > 0) {
|
|
@@ -291,6 +383,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
291
383
|
formData.append('message[attachments][]', file);
|
|
292
384
|
});
|
|
293
385
|
formData.append('session', _hellotext.default.session);
|
|
386
|
+
formData.append('locale', _core.Locale.toString());
|
|
294
387
|
const element = this.messageTemplateTarget.cloneNode(true);
|
|
295
388
|
element.id = `hellotext--webchat--${this.idValue}--message--${Date.now()}`;
|
|
296
389
|
element.classList.add('received');
|
|
@@ -307,7 +400,13 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
307
400
|
element.querySelector('[data-attachment-container]').appendChild(attachment);
|
|
308
401
|
});
|
|
309
402
|
}
|
|
310
|
-
|
|
403
|
+
|
|
404
|
+
// Insert message before typing indicator if one exists
|
|
405
|
+
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
406
|
+
this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
|
|
407
|
+
} else {
|
|
408
|
+
this.messagesContainerTarget.appendChild(element);
|
|
409
|
+
}
|
|
311
410
|
element.scrollIntoView({
|
|
312
411
|
behavior: 'smooth'
|
|
313
412
|
});
|
|
@@ -316,6 +415,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
316
415
|
element: element.outerHTML
|
|
317
416
|
});
|
|
318
417
|
this.inputTarget.value = '';
|
|
418
|
+
this.resizeInput();
|
|
319
419
|
this.files = [];
|
|
320
420
|
this.attachmentInputTarget.value = '';
|
|
321
421
|
this.attachmentContainerTarget.innerHTML = '';
|
|
@@ -338,6 +438,14 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
338
438
|
this.conversationIdValue = data.conversation;
|
|
339
439
|
this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
|
|
340
440
|
}
|
|
441
|
+
if (this.typingIndicatorVisible) {
|
|
442
|
+
this.resetTypingIndicatorTimer();
|
|
443
|
+
} else {
|
|
444
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
445
|
+
this.optimisticTypingTimeout = setTimeout(() => {
|
|
446
|
+
this.showOptimisticTypingIndicator();
|
|
447
|
+
}, this.optimisticTypingIndicatorWaitValue);
|
|
448
|
+
}
|
|
341
449
|
this.attachmentContainerTarget.style.display = '';
|
|
342
450
|
}
|
|
343
451
|
}, {
|
|
@@ -434,30 +542,27 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
434
542
|
this.inputTarget.selectionStart = this.inputTarget.selectionEnd = start + emoji.length;
|
|
435
543
|
this.inputTarget.focus();
|
|
436
544
|
}
|
|
437
|
-
}, {
|
|
438
|
-
key: "setOfflineTimeout",
|
|
439
|
-
value: function setOfflineTimeout() {
|
|
440
|
-
clearTimeout(this.offlineTimeout);
|
|
441
|
-
this.offlineTimeout = setTimeout(() => {
|
|
442
|
-
this.onlineStatusTarget.style.display = 'none';
|
|
443
|
-
}, this.fiveMinutes);
|
|
444
|
-
}
|
|
445
545
|
}, {
|
|
446
546
|
key: "byteToMegabyte",
|
|
447
547
|
value: function byteToMegabyte(bytes) {
|
|
448
548
|
return Math.ceil(bytes / 1024 / 1024);
|
|
449
549
|
}
|
|
450
550
|
}, {
|
|
451
|
-
key: "
|
|
551
|
+
key: "middlewares",
|
|
452
552
|
get: function () {
|
|
453
|
-
return
|
|
553
|
+
return [(0, _dom.offset)(this.offsetValue), (0, _dom.shift)({
|
|
554
|
+
padding: this.paddingValue
|
|
555
|
+
}), (0, _dom.flip)()];
|
|
454
556
|
}
|
|
455
557
|
}, {
|
|
456
|
-
key: "
|
|
558
|
+
key: "shouldOpenOnMount",
|
|
457
559
|
get: function () {
|
|
458
|
-
return
|
|
459
|
-
|
|
460
|
-
|
|
560
|
+
return localStorage.getItem(`hellotext--webchat--${this.idValue}`) === 'opened' && !this.onMobile;
|
|
561
|
+
}
|
|
562
|
+
}, {
|
|
563
|
+
key: "onMobile",
|
|
564
|
+
get: function () {
|
|
565
|
+
return window.matchMedia(`(max-width: ${this.fullScreenThresholdValue}px)`).matches;
|
|
461
566
|
}
|
|
462
567
|
}]);
|
|
463
568
|
return _default;
|
|
@@ -487,6 +592,28 @@ _default.values = {
|
|
|
487
592
|
nextPage: {
|
|
488
593
|
type: Number,
|
|
489
594
|
default: undefined
|
|
490
|
-
}
|
|
595
|
+
},
|
|
596
|
+
fullScreenThreshold: {
|
|
597
|
+
type: Number,
|
|
598
|
+
default: 1024
|
|
599
|
+
},
|
|
600
|
+
typingIndicatorKeepAlive: {
|
|
601
|
+
type: Number,
|
|
602
|
+
default: 30000
|
|
603
|
+
},
|
|
604
|
+
// 30 seconds
|
|
605
|
+
offset: {
|
|
606
|
+
type: Number,
|
|
607
|
+
default: 24
|
|
608
|
+
},
|
|
609
|
+
padding: {
|
|
610
|
+
type: Number,
|
|
611
|
+
default: 24
|
|
612
|
+
},
|
|
613
|
+
optimisticTypingIndicatorWait: {
|
|
614
|
+
type: Number,
|
|
615
|
+
default: 1000
|
|
616
|
+
} // 1 second
|
|
491
617
|
};
|
|
492
|
-
_default.
|
|
618
|
+
_default.classes = ['fadeOut'];
|
|
619
|
+
_default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate'];
|