@hellotext/hellotext 2.1.3 → 2.1.5
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/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_controller.cjs +145 -42
- package/lib/controllers/webchat_controller.js +146 -43
- package/lib/core/configuration.cjs +1 -0
- package/lib/core/configuration.js +1 -0
- package/lib/hellotext.cjs +3 -1
- package/lib/hellotext.js +4 -4
- package/lib/models/index.cjs +14 -0
- package/lib/models/index.js +2 -0
- package/lib/models/page.cjs +86 -0
- package/lib/models/page.js +81 -0
- 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/lib/models/utm.cjs +41 -0
- package/lib/models/utm.js +38 -0
- package/package.json +1 -1
- package/src/channels/application_channel.js +12 -9
- package/src/channels/webchat_channel.js +33 -19
- package/src/controllers/webchat_controller.js +137 -34
- package/src/core/configuration.js +1 -0
- package/src/hellotext.js +5 -2
- package/src/models/cookies.js +2 -2
- package/src/models/index.js +2 -0
- package/src/models/page.js +65 -0
- package/src/models/query.js +1 -3
- package/src/models/session.js +1 -1
- package/src/models/utm.js +33 -0
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _core = require("../core");
|
|
7
8
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
8
9
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
9
10
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
@@ -17,17 +18,19 @@ let ApplicationChannel = /*#__PURE__*/function () {
|
|
|
17
18
|
key: "send",
|
|
18
19
|
value: function send({
|
|
19
20
|
command,
|
|
20
|
-
identifier
|
|
21
|
+
identifier,
|
|
22
|
+
data
|
|
21
23
|
}) {
|
|
22
|
-
const
|
|
24
|
+
const payload = {
|
|
23
25
|
command,
|
|
24
|
-
identifier: JSON.stringify(identifier)
|
|
26
|
+
identifier: JSON.stringify(identifier),
|
|
27
|
+
data: JSON.stringify(data || {})
|
|
25
28
|
};
|
|
26
29
|
if (this.webSocket.readyState === WebSocket.OPEN) {
|
|
27
|
-
this.webSocket.send(JSON.stringify(
|
|
30
|
+
this.webSocket.send(JSON.stringify(payload));
|
|
28
31
|
} else {
|
|
29
32
|
this.webSocket.addEventListener('open', () => {
|
|
30
|
-
this.webSocket.send(JSON.stringify(
|
|
33
|
+
this.webSocket.send(JSON.stringify(payload));
|
|
31
34
|
});
|
|
32
35
|
}
|
|
33
36
|
}
|
|
@@ -50,7 +53,7 @@ let ApplicationChannel = /*#__PURE__*/function () {
|
|
|
50
53
|
key: "webSocket",
|
|
51
54
|
get: function () {
|
|
52
55
|
if (!ApplicationChannel.webSocket) {
|
|
53
|
-
return ApplicationChannel.webSocket = new WebSocket(
|
|
56
|
+
return ApplicationChannel.webSocket = new WebSocket(_core.Configuration.actionCableUrl);
|
|
54
57
|
}
|
|
55
58
|
return ApplicationChannel.webSocket;
|
|
56
59
|
}
|
|
@@ -3,6 +3,7 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
|
|
|
3
3
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
4
4
|
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
5
5
|
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
6
|
+
import { Configuration } from '../core';
|
|
6
7
|
var ApplicationChannel = /*#__PURE__*/function () {
|
|
7
8
|
function ApplicationChannel() {
|
|
8
9
|
_classCallCheck(this, ApplicationChannel);
|
|
@@ -12,17 +13,19 @@ var ApplicationChannel = /*#__PURE__*/function () {
|
|
|
12
13
|
value: function send(_ref) {
|
|
13
14
|
var {
|
|
14
15
|
command,
|
|
15
|
-
identifier
|
|
16
|
+
identifier,
|
|
17
|
+
data
|
|
16
18
|
} = _ref;
|
|
17
|
-
var
|
|
19
|
+
var payload = {
|
|
18
20
|
command,
|
|
19
|
-
identifier: JSON.stringify(identifier)
|
|
21
|
+
identifier: JSON.stringify(identifier),
|
|
22
|
+
data: JSON.stringify(data || {})
|
|
20
23
|
};
|
|
21
24
|
if (this.webSocket.readyState === WebSocket.OPEN) {
|
|
22
|
-
this.webSocket.send(JSON.stringify(
|
|
25
|
+
this.webSocket.send(JSON.stringify(payload));
|
|
23
26
|
} else {
|
|
24
27
|
this.webSocket.addEventListener('open', () => {
|
|
25
|
-
this.webSocket.send(JSON.stringify(
|
|
28
|
+
this.webSocket.send(JSON.stringify(payload));
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -45,7 +48,7 @@ var ApplicationChannel = /*#__PURE__*/function () {
|
|
|
45
48
|
key: "webSocket",
|
|
46
49
|
get: function get() {
|
|
47
50
|
if (!ApplicationChannel.webSocket) {
|
|
48
|
-
return ApplicationChannel.webSocket = new WebSocket(
|
|
51
|
+
return ApplicationChannel.webSocket = new WebSocket(Configuration.actionCableUrl);
|
|
49
52
|
}
|
|
50
53
|
return ApplicationChannel.webSocket;
|
|
51
54
|
}
|
|
@@ -37,7 +37,7 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
37
37
|
key: "subscribe",
|
|
38
38
|
value: function subscribe() {
|
|
39
39
|
const params = {
|
|
40
|
-
channel:
|
|
40
|
+
channel: 'WebchatChannel',
|
|
41
41
|
id: this.id,
|
|
42
42
|
session: this.session,
|
|
43
43
|
conversation: this.conversation
|
|
@@ -51,7 +51,7 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
51
51
|
key: "unsubscribe",
|
|
52
52
|
value: function unsubscribe() {
|
|
53
53
|
const params = {
|
|
54
|
-
channel:
|
|
54
|
+
channel: 'WebchatChannel',
|
|
55
55
|
id: this.id,
|
|
56
56
|
session: this.session,
|
|
57
57
|
conversation: this.conversation
|
|
@@ -62,29 +62,45 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
}, {
|
|
65
|
-
key: "
|
|
66
|
-
value: function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
key: "startTypingIndicator",
|
|
66
|
+
value: function startTypingIndicator() {
|
|
67
|
+
const params = {
|
|
68
|
+
channel: 'WebchatChannel',
|
|
69
|
+
id: this.id,
|
|
70
|
+
session: this.session,
|
|
71
|
+
conversation: this.conversation
|
|
72
|
+
};
|
|
73
|
+
this.send({
|
|
74
|
+
command: 'message',
|
|
75
|
+
identifier: params,
|
|
76
|
+
data: {
|
|
77
|
+
action: 'started_typing'
|
|
78
|
+
}
|
|
70
79
|
});
|
|
71
80
|
}
|
|
72
81
|
}, {
|
|
73
|
-
key: "
|
|
74
|
-
value: function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
key: "stopTypingIndicator",
|
|
83
|
+
value: function stopTypingIndicator() {
|
|
84
|
+
const params = {
|
|
85
|
+
channel: 'WebchatChannel',
|
|
86
|
+
id: this.id,
|
|
87
|
+
session: this.session,
|
|
88
|
+
conversation: this.conversation
|
|
89
|
+
};
|
|
90
|
+
this.send({
|
|
91
|
+
command: 'typing:stop',
|
|
92
|
+
identifier: params,
|
|
93
|
+
data: {
|
|
94
|
+
action: 'stopped_typing'
|
|
78
95
|
}
|
|
79
96
|
});
|
|
80
97
|
}
|
|
81
98
|
}, {
|
|
82
|
-
key: "
|
|
83
|
-
value: function
|
|
99
|
+
key: "onMessage",
|
|
100
|
+
value: function onMessage(callback) {
|
|
84
101
|
_get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
|
|
85
|
-
if (message.type
|
|
86
|
-
|
|
87
|
-
}
|
|
102
|
+
if (message.type !== 'message') return;
|
|
103
|
+
callback(message);
|
|
88
104
|
});
|
|
89
105
|
}
|
|
90
106
|
}, {
|
|
@@ -96,6 +112,15 @@ let WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
96
112
|
}
|
|
97
113
|
});
|
|
98
114
|
}
|
|
115
|
+
}, {
|
|
116
|
+
key: "onTypingStart",
|
|
117
|
+
value: function onTypingStart(callback) {
|
|
118
|
+
_get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
|
|
119
|
+
if (message.type === 'started_typing') {
|
|
120
|
+
callback(message);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
99
124
|
}, {
|
|
100
125
|
key: "updateSubscriptionWith",
|
|
101
126
|
value: function updateSubscriptionWith(conversation) {
|
|
@@ -30,7 +30,7 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
30
30
|
key: "subscribe",
|
|
31
31
|
value: function subscribe() {
|
|
32
32
|
var params = {
|
|
33
|
-
channel:
|
|
33
|
+
channel: 'WebchatChannel',
|
|
34
34
|
id: this.id,
|
|
35
35
|
session: this.session,
|
|
36
36
|
conversation: this.conversation
|
|
@@ -44,7 +44,7 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
44
44
|
key: "unsubscribe",
|
|
45
45
|
value: function unsubscribe() {
|
|
46
46
|
var params = {
|
|
47
|
-
channel:
|
|
47
|
+
channel: 'WebchatChannel',
|
|
48
48
|
id: this.id,
|
|
49
49
|
session: this.session,
|
|
50
50
|
conversation: this.conversation
|
|
@@ -55,29 +55,45 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
}, {
|
|
58
|
-
key: "
|
|
59
|
-
value: function
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
key: "startTypingIndicator",
|
|
59
|
+
value: function startTypingIndicator() {
|
|
60
|
+
var params = {
|
|
61
|
+
channel: 'WebchatChannel',
|
|
62
|
+
id: this.id,
|
|
63
|
+
session: this.session,
|
|
64
|
+
conversation: this.conversation
|
|
65
|
+
};
|
|
66
|
+
this.send({
|
|
67
|
+
command: 'message',
|
|
68
|
+
identifier: params,
|
|
69
|
+
data: {
|
|
70
|
+
action: 'started_typing'
|
|
71
|
+
}
|
|
63
72
|
});
|
|
64
73
|
}
|
|
65
74
|
}, {
|
|
66
|
-
key: "
|
|
67
|
-
value: function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
key: "stopTypingIndicator",
|
|
76
|
+
value: function stopTypingIndicator() {
|
|
77
|
+
var params = {
|
|
78
|
+
channel: 'WebchatChannel',
|
|
79
|
+
id: this.id,
|
|
80
|
+
session: this.session,
|
|
81
|
+
conversation: this.conversation
|
|
82
|
+
};
|
|
83
|
+
this.send({
|
|
84
|
+
command: 'typing:stop',
|
|
85
|
+
identifier: params,
|
|
86
|
+
data: {
|
|
87
|
+
action: 'stopped_typing'
|
|
71
88
|
}
|
|
72
89
|
});
|
|
73
90
|
}
|
|
74
91
|
}, {
|
|
75
|
-
key: "
|
|
76
|
-
value: function
|
|
92
|
+
key: "onMessage",
|
|
93
|
+
value: function onMessage(callback) {
|
|
77
94
|
_get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
|
|
78
|
-
if (message.type
|
|
79
|
-
|
|
80
|
-
}
|
|
95
|
+
if (message.type !== 'message') return;
|
|
96
|
+
callback(message);
|
|
81
97
|
});
|
|
82
98
|
}
|
|
83
99
|
}, {
|
|
@@ -89,6 +105,15 @@ var WebchatChannel = /*#__PURE__*/function (_ApplicationChannel) {
|
|
|
89
105
|
}
|
|
90
106
|
});
|
|
91
107
|
}
|
|
108
|
+
}, {
|
|
109
|
+
key: "onTypingStart",
|
|
110
|
+
value: function onTypingStart(callback) {
|
|
111
|
+
_get(_getPrototypeOf(WebchatChannel.prototype), "onMessage", this).call(this, message => {
|
|
112
|
+
if (message.type === 'started_typing') {
|
|
113
|
+
callback(message);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
92
117
|
}, {
|
|
93
118
|
key: "updateSubscriptionWith",
|
|
94
119
|
value: function updateSubscriptionWith(conversation) {
|
|
@@ -42,9 +42,8 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
42
42
|
this.webChatChannel = new _webchat_channel.default(this.idValue, _hellotext.default.session, this.conversationIdValue);
|
|
43
43
|
this.files = [];
|
|
44
44
|
this.onMessageReceived = this.onMessageReceived.bind(this);
|
|
45
|
-
this.onConversationAssignment = this.onConversationAssignment.bind(this);
|
|
46
|
-
this.onAgentOnline = this.onAgentOnline.bind(this);
|
|
47
45
|
this.onMessageReaction = this.onMessageReaction.bind(this);
|
|
46
|
+
this.onTypingStart = this.onTypingStart.bind(this);
|
|
48
47
|
this.onScroll = this.onScroll.bind(this);
|
|
49
48
|
this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
|
|
50
49
|
this.broadcastChannel = new BroadcastChannel(`hellotext--webchat--${this.idValue}`);
|
|
@@ -61,8 +60,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
61
60
|
popover: this.popoverTarget
|
|
62
61
|
});
|
|
63
62
|
this.webChatChannel.onMessage(this.onMessageReceived);
|
|
64
|
-
this.webChatChannel.
|
|
65
|
-
this.webChatChannel.onAgentOnline(this.onAgentOnline);
|
|
63
|
+
this.webChatChannel.onTypingStart(this.onTypingStart);
|
|
66
64
|
this.webChatChannel.onReaction(this.onMessageReaction);
|
|
67
65
|
this.messagesContainerTarget.addEventListener('scroll', this.onScroll);
|
|
68
66
|
if (!_hellotext.default.business.features.white_label) {
|
|
@@ -80,10 +78,85 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
80
78
|
value: function disconnect() {
|
|
81
79
|
this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
|
|
82
80
|
this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
|
|
81
|
+
|
|
82
|
+
// Clean up typing indicator timeouts
|
|
83
|
+
this.clearTypingIndicator();
|
|
83
84
|
this.broadcastChannel.close();
|
|
84
85
|
this.floatingUICleanup();
|
|
85
86
|
_get(_getPrototypeOf(_default.prototype), "disconnect", this).call(this);
|
|
86
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
|
+
}
|
|
87
160
|
}, {
|
|
88
161
|
key: "onOutboundMessageSent",
|
|
89
162
|
value: function onOutboundMessageSent(event) {
|
|
@@ -93,7 +166,13 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
93
166
|
const callbacks = {
|
|
94
167
|
'message:sent': data => {
|
|
95
168
|
const element = new DOMParser().parseFromString(data.element, 'text/html').body.firstElementChild;
|
|
96
|
-
|
|
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
|
+
}
|
|
97
176
|
element.scrollIntoView({
|
|
98
177
|
behavior: 'instant'
|
|
99
178
|
});
|
|
@@ -247,6 +326,7 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
247
326
|
element.querySelector('[data-attachment-container]').appendChild(image);
|
|
248
327
|
});
|
|
249
328
|
}
|
|
329
|
+
this.clearTypingIndicator();
|
|
250
330
|
this.messagesContainerTarget.appendChild(element);
|
|
251
331
|
_hellotext.default.eventEmitter.dispatch('webchat:message:received', {
|
|
252
332
|
...message,
|
|
@@ -255,7 +335,6 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
255
335
|
element.scrollIntoView({
|
|
256
336
|
behavior: 'smooth'
|
|
257
337
|
});
|
|
258
|
-
this.setOfflineTimeout();
|
|
259
338
|
if (this.openValue) {
|
|
260
339
|
this.messagesAPI.markAsSeen(id);
|
|
261
340
|
return;
|
|
@@ -265,33 +344,30 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
265
344
|
this.unreadCounterTarget.innerText = unreadCount > 99 ? '99+' : unreadCount;
|
|
266
345
|
}
|
|
267
346
|
}, {
|
|
268
|
-
key: "
|
|
269
|
-
value: function
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}, {
|
|
281
|
-
key: "onAgentOnline",
|
|
282
|
-
value: function onAgentOnline() {
|
|
283
|
-
this.onlineStatusTarget.style.display = 'flex';
|
|
284
|
-
this.setOfflineTimeout();
|
|
347
|
+
key: "resizeInput",
|
|
348
|
+
value: function resizeInput() {
|
|
349
|
+
const maxHeight = 96;
|
|
350
|
+
|
|
351
|
+
// Temporarily reset height to its natural content size
|
|
352
|
+
this.inputTarget.style.height = 'auto';
|
|
353
|
+
|
|
354
|
+
// Set the height to the scrollHeight, which is the minimum height
|
|
355
|
+
// the element needs to fit its content without a scrollbar.
|
|
356
|
+
const scrollHeight = this.inputTarget.scrollHeight;
|
|
357
|
+
this.inputTarget.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
|
|
285
358
|
}
|
|
286
359
|
}, {
|
|
287
360
|
key: "sendMessage",
|
|
288
|
-
value: async function sendMessage() {
|
|
361
|
+
value: async function sendMessage(e) {
|
|
289
362
|
const formData = new FormData();
|
|
290
363
|
const message = {
|
|
291
364
|
body: this.inputTarget.value,
|
|
292
365
|
attachments: this.files
|
|
293
366
|
};
|
|
294
367
|
if (this.inputTarget.value.trim().length === 0 && this.files.length === 0) {
|
|
368
|
+
if (e && e.target) {
|
|
369
|
+
e.preventDefault();
|
|
370
|
+
}
|
|
295
371
|
return;
|
|
296
372
|
}
|
|
297
373
|
if (this.inputTarget.value.trim().length > 0) {
|
|
@@ -320,7 +396,13 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
320
396
|
element.querySelector('[data-attachment-container]').appendChild(attachment);
|
|
321
397
|
});
|
|
322
398
|
}
|
|
323
|
-
|
|
399
|
+
|
|
400
|
+
// Insert message before typing indicator if one exists
|
|
401
|
+
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
402
|
+
this.messagesContainerTarget.insertBefore(element, this.typingIndicatorTarget);
|
|
403
|
+
} else {
|
|
404
|
+
this.messagesContainerTarget.appendChild(element);
|
|
405
|
+
}
|
|
324
406
|
element.scrollIntoView({
|
|
325
407
|
behavior: 'smooth'
|
|
326
408
|
});
|
|
@@ -329,14 +411,26 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
329
411
|
element: element.outerHTML
|
|
330
412
|
});
|
|
331
413
|
this.inputTarget.value = '';
|
|
414
|
+
this.resizeInput();
|
|
332
415
|
this.files = [];
|
|
333
416
|
this.attachmentInputTarget.value = '';
|
|
334
417
|
this.attachmentContainerTarget.innerHTML = '';
|
|
335
418
|
this.attachmentContainerTarget.style.display = 'none';
|
|
336
419
|
this.errorMessageContainerTarget.style.display = 'none';
|
|
337
420
|
this.inputTarget.focus();
|
|
421
|
+
|
|
422
|
+
// Set up optimistic typing indicator BEFORE making the API call
|
|
423
|
+
// This prevents race conditions with server responses
|
|
424
|
+
if (!this.typingIndicatorVisible) {
|
|
425
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
426
|
+
this.optimisticTypingTimeout = setTimeout(() => {
|
|
427
|
+
this.showOptimisticTypingIndicator();
|
|
428
|
+
}, this.optimisticTypingIndicatorWaitValue);
|
|
429
|
+
}
|
|
338
430
|
const response = await this.messagesAPI.create(formData);
|
|
339
431
|
if (response.failed) {
|
|
432
|
+
// Clear the optimistic typing indicator on failure
|
|
433
|
+
clearTimeout(this.optimisticTypingTimeout);
|
|
340
434
|
this.broadcastChannel.postMessage({
|
|
341
435
|
type: 'message:failed',
|
|
342
436
|
id: element.id
|
|
@@ -351,6 +445,11 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
351
445
|
this.conversationIdValue = data.conversation;
|
|
352
446
|
this.webChatChannel.updateSubscriptionWith(this.conversationIdValue);
|
|
353
447
|
}
|
|
448
|
+
|
|
449
|
+
// If there's already a typing indicator visible, reset its timer
|
|
450
|
+
if (this.typingIndicatorVisible) {
|
|
451
|
+
this.resetTypingIndicatorTimer();
|
|
452
|
+
}
|
|
354
453
|
this.attachmentContainerTarget.style.display = '';
|
|
355
454
|
}
|
|
356
455
|
}, {
|
|
@@ -447,29 +546,16 @@ let _default = /*#__PURE__*/function (_Controller) {
|
|
|
447
546
|
this.inputTarget.selectionStart = this.inputTarget.selectionEnd = start + emoji.length;
|
|
448
547
|
this.inputTarget.focus();
|
|
449
548
|
}
|
|
450
|
-
}, {
|
|
451
|
-
key: "setOfflineTimeout",
|
|
452
|
-
value: function setOfflineTimeout() {
|
|
453
|
-
clearTimeout(this.offlineTimeout);
|
|
454
|
-
this.offlineTimeout = setTimeout(() => {
|
|
455
|
-
this.onlineStatusTarget.style.display = 'none';
|
|
456
|
-
}, this.fiveMinutes);
|
|
457
|
-
}
|
|
458
549
|
}, {
|
|
459
550
|
key: "byteToMegabyte",
|
|
460
551
|
value: function byteToMegabyte(bytes) {
|
|
461
552
|
return Math.ceil(bytes / 1024 / 1024);
|
|
462
553
|
}
|
|
463
|
-
}, {
|
|
464
|
-
key: "fiveMinutes",
|
|
465
|
-
get: function () {
|
|
466
|
-
return 300000;
|
|
467
|
-
}
|
|
468
554
|
}, {
|
|
469
555
|
key: "middlewares",
|
|
470
556
|
get: function () {
|
|
471
|
-
return [(0, _dom.offset)(
|
|
472
|
-
padding:
|
|
557
|
+
return [(0, _dom.offset)(this.offsetValue), (0, _dom.shift)({
|
|
558
|
+
padding: this.paddingValue
|
|
473
559
|
}), (0, _dom.flip)()];
|
|
474
560
|
}
|
|
475
561
|
}, {
|
|
@@ -514,7 +600,24 @@ _default.values = {
|
|
|
514
600
|
fullScreenThreshold: {
|
|
515
601
|
type: Number,
|
|
516
602
|
default: 1024
|
|
517
|
-
}
|
|
603
|
+
},
|
|
604
|
+
typingIndicatorKeepAlive: {
|
|
605
|
+
type: Number,
|
|
606
|
+
default: 30000
|
|
607
|
+
},
|
|
608
|
+
// 30 seconds
|
|
609
|
+
offset: {
|
|
610
|
+
type: Number,
|
|
611
|
+
default: 24
|
|
612
|
+
},
|
|
613
|
+
padding: {
|
|
614
|
+
type: Number,
|
|
615
|
+
default: 24
|
|
616
|
+
},
|
|
617
|
+
optimisticTypingIndicatorWait: {
|
|
618
|
+
type: Number,
|
|
619
|
+
default: 1000
|
|
620
|
+
} // 1 second
|
|
518
621
|
};
|
|
519
622
|
_default.classes = ['fadeOut'];
|
|
520
|
-
_default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', '
|
|
623
|
+
_default.targets = ['trigger', 'popover', 'input', 'attachmentInput', 'attachmentButton', 'errorMessageContainer', 'attachmentTemplate', 'attachmentContainer', 'attachment', 'messageTemplate', 'messagesContainer', 'title', 'attachmentImage', 'footer', 'toolbar', 'message', 'unreadCounter', 'typingIndicator', 'typingIndicatorTemplate'];
|