@hellotext/hellotext 2.4.1 → 2.4.3
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/controllers/message_controller.cjs +167 -31
- package/lib/controllers/message_controller.js +169 -33
- package/lib/controllers/mixins/usePopover.cjs +2 -0
- package/lib/controllers/mixins/usePopover.js +2 -0
- package/lib/controllers/webchat/useTeaser.cjs +3 -1
- package/lib/controllers/webchat/useTeaser.js +3 -1
- package/lib/controllers/webchat_controller.cjs +195 -25
- package/lib/controllers/webchat_controller.js +209 -25
- package/lib/core/configuration.cjs +19 -0
- package/lib/core/configuration.js +19 -0
- package/lib/models/business.cjs +86 -5
- package/lib/models/business.js +82 -5
- package/lib/models/webchat.cjs +18 -3
- package/lib/models/webchat.js +27 -6
- package/package.json +1 -1
- package/src/controllers/message_controller.js +155 -29
- package/src/controllers/mixins/usePopover.js +1 -0
- package/src/controllers/webchat/useTeaser.js +4 -1
- package/src/controllers/webchat_controller.js +219 -27
- package/src/core/configuration.js +25 -0
- package/src/models/business.js +86 -5
- package/src/models/webchat.js +22 -3
|
@@ -28,6 +28,11 @@ import { usePopover } from './mixins/usePopover';
|
|
|
28
28
|
import { useBehaviour } from './webchat/useBehaviour';
|
|
29
29
|
import { useOpeningSequence } from './webchat/useOpeningSequence';
|
|
30
30
|
import { useTeaser } from './webchat/useTeaser';
|
|
31
|
+
var POPOVER_ANIMATION_DURATION = 120;
|
|
32
|
+
var MESSAGE_TIMESTAMP_FORMAT_OPTIONS = {
|
|
33
|
+
hour: 'numeric',
|
|
34
|
+
minute: '2-digit'
|
|
35
|
+
};
|
|
31
36
|
var _default = /*#__PURE__*/function (_Controller) {
|
|
32
37
|
_inherits(_default, _Controller);
|
|
33
38
|
var _super = _createSuper(_default);
|
|
@@ -47,6 +52,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
47
52
|
this.onTypingStart = this.onTypingStart.bind(this);
|
|
48
53
|
this.onScroll = this.onScroll.bind(this);
|
|
49
54
|
this.onOutboundMessageSent = this.onOutboundMessageSent.bind(this);
|
|
55
|
+
this.closePopoverOnEscape = this.closePopoverOnEscape.bind(this);
|
|
50
56
|
this.broadcastChannel = new BroadcastChannel("hellotext--webchat--".concat(this.idValue));
|
|
51
57
|
_get(_getPrototypeOf(_default.prototype), "initialize", this).call(this);
|
|
52
58
|
}
|
|
@@ -70,6 +76,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
70
76
|
}
|
|
71
77
|
this.setupTeaser();
|
|
72
78
|
this.setupOpeningSequence();
|
|
79
|
+
this.localizeMessageTimestamps();
|
|
73
80
|
this.webChatChannel.onMessage(this.onMessageReceived);
|
|
74
81
|
this.webChatChannel.onTypingStart(this.onTypingStart);
|
|
75
82
|
this.webChatChannel.onReaction(this.onMessageReaction);
|
|
@@ -79,6 +86,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
79
86
|
}
|
|
80
87
|
Hellotext.eventEmitter.dispatch('webchat:mounted');
|
|
81
88
|
this.broadcastChannel.addEventListener('message', this.onOutboundMessageSent);
|
|
89
|
+
window.addEventListener('keydown', this.closePopoverOnEscape, true);
|
|
82
90
|
this.scheduleBehaviourOpen();
|
|
83
91
|
_get(_getPrototypeOf(_default.prototype), "connect", this).call(this);
|
|
84
92
|
}
|
|
@@ -86,10 +94,12 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
86
94
|
key: "disconnect",
|
|
87
95
|
value: function disconnect() {
|
|
88
96
|
this.cancelBehaviourOpen();
|
|
97
|
+
this.clearPopoverOpenAnimation();
|
|
89
98
|
this.teardownTeaser();
|
|
90
99
|
this.teardownOpeningSequence();
|
|
91
100
|
this.broadcastChannel.removeEventListener('message', this.onOutboundMessageSent);
|
|
92
101
|
this.messagesContainerTarget.removeEventListener('scroll', this.onScroll);
|
|
102
|
+
window.removeEventListener('keydown', this.closePopoverOnEscape, true);
|
|
93
103
|
|
|
94
104
|
// Clean up typing indicator timeouts
|
|
95
105
|
this.clearTypingIndicator();
|
|
@@ -178,6 +188,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
178
188
|
var callbacks = {
|
|
179
189
|
'message:sent': data => {
|
|
180
190
|
var element = new DOMParser().parseFromString(data.element, 'text/html').body.firstElementChild;
|
|
191
|
+
this.localizeMessageTimestamps(element);
|
|
181
192
|
|
|
182
193
|
// Insert message before typing indicator if one exists
|
|
183
194
|
if (this.typingIndicatorVisible && this.hasTypingIndicatorTarget) {
|
|
@@ -190,8 +201,8 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
190
201
|
});
|
|
191
202
|
},
|
|
192
203
|
'message:failed': data => {
|
|
193
|
-
var
|
|
194
|
-
|
|
204
|
+
var element = this.messagesContainerTarget.querySelector("#".concat(data.id));
|
|
205
|
+
this.markMessageFailed(element, data.reason);
|
|
195
206
|
}
|
|
196
207
|
};
|
|
197
208
|
if (callbacks[data.type]) {
|
|
@@ -221,6 +232,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
221
232
|
body,
|
|
222
233
|
attachments
|
|
223
234
|
} = message;
|
|
235
|
+
var createdAt = message.created_at || message.createdAt;
|
|
224
236
|
var div = document.createElement('div');
|
|
225
237
|
div.innerHTML = body;
|
|
226
238
|
var element = this.messageTemplateTarget.cloneNode(true);
|
|
@@ -243,6 +255,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
243
255
|
});
|
|
244
256
|
}
|
|
245
257
|
element.setAttribute('data-body', body);
|
|
258
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), createdAt);
|
|
246
259
|
this.messagesContainerTarget.prepend(element);
|
|
247
260
|
});
|
|
248
261
|
this.messagesContainerTarget.scroll({
|
|
@@ -266,10 +279,30 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
266
279
|
}, {
|
|
267
280
|
key: "closePopover",
|
|
268
281
|
value: function closePopover() {
|
|
269
|
-
this.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
282
|
+
this.clearPopoverOpenAnimation();
|
|
283
|
+
this.popoverTarget.classList.remove(...this.fadeOutClasses);
|
|
284
|
+
this.openValue = false;
|
|
285
|
+
}
|
|
286
|
+
}, {
|
|
287
|
+
key: "preparePopoverOpenAnimation",
|
|
288
|
+
value: function preparePopoverOpenAnimation() {
|
|
289
|
+
this.clearPopoverOpenAnimation();
|
|
290
|
+
this.popoverTarget.classList.remove(...this.fadeOutClasses);
|
|
291
|
+
this.popoverTarget.classList.add('hellotext--webchat-popover-opening');
|
|
292
|
+
this.popoverOpenAnimationTimeout = setTimeout(() => {
|
|
293
|
+
this.popoverTarget.classList.remove('hellotext--webchat-popover-opening');
|
|
294
|
+
this.popoverOpenAnimationTimeout = null;
|
|
295
|
+
}, POPOVER_ANIMATION_DURATION);
|
|
296
|
+
}
|
|
297
|
+
}, {
|
|
298
|
+
key: "clearPopoverOpenAnimation",
|
|
299
|
+
value: function clearPopoverOpenAnimation() {
|
|
300
|
+
var _this$popoverTarget;
|
|
301
|
+
if (this.popoverOpenAnimationTimeout) {
|
|
302
|
+
clearTimeout(this.popoverOpenAnimationTimeout);
|
|
303
|
+
this.popoverOpenAnimationTimeout = null;
|
|
304
|
+
}
|
|
305
|
+
(_this$popoverTarget = this.popoverTarget) === null || _this$popoverTarget === void 0 ? void 0 : _this$popoverTarget.classList.remove('hellotext--webchat-popover-opening');
|
|
273
306
|
}
|
|
274
307
|
}, {
|
|
275
308
|
key: "onPopoverOpened",
|
|
@@ -303,6 +336,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
303
336
|
}, {
|
|
304
337
|
key: "onPopoverClosed",
|
|
305
338
|
value: function onPopoverClosed() {
|
|
339
|
+
this.clearPopoverOpenAnimation();
|
|
306
340
|
Hellotext.eventEmitter.dispatch('webchat:closed');
|
|
307
341
|
localStorage.setItem("hellotext--webchat--".concat(this.idValue), 'closed');
|
|
308
342
|
}
|
|
@@ -340,6 +374,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
340
374
|
attachments,
|
|
341
375
|
teaser
|
|
342
376
|
} = message;
|
|
377
|
+
var createdAt = message.created_at || message.createdAt;
|
|
343
378
|
if (!this.claimMessageId(id)) return;
|
|
344
379
|
(_this$hideTeaser = this.hideTeaser) === null || _this$hideTeaser === void 0 ? void 0 : _this$hideTeaser.call(this);
|
|
345
380
|
if (message.carousel) {
|
|
@@ -352,6 +387,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
352
387
|
element.querySelector('[data-body]').innerHTML = div.innerHTML;
|
|
353
388
|
element.setAttribute('data-id', id);
|
|
354
389
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
390
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), createdAt);
|
|
355
391
|
if (attachments) {
|
|
356
392
|
attachments.forEach(attachmentUrl => {
|
|
357
393
|
var _this$messageAttachme2;
|
|
@@ -408,6 +444,7 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
408
444
|
var element = new DOMParser().parseFromString(html, 'text/html').body.firstElementChild;
|
|
409
445
|
element.setAttribute('data-id', message.id);
|
|
410
446
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
447
|
+
this.localizeMessageTimestamps(element);
|
|
411
448
|
this.clearTypingIndicator();
|
|
412
449
|
this.messagesContainerTarget.appendChild(element);
|
|
413
450
|
element.scrollIntoView({
|
|
@@ -453,14 +490,14 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
453
490
|
(_this$dismissTeaserFo2 = this.dismissTeaserForSession) === null || _this$dismissTeaserFo2 === void 0 ? void 0 : _this$dismissTeaserFo2.call(this);
|
|
454
491
|
var formData = new FormData();
|
|
455
492
|
formData.append('message[body]', body);
|
|
456
|
-
formData.append('message[replied_to]', id);
|
|
457
|
-
formData.append('message[product]', product);
|
|
458
|
-
formData.append('message[button]', buttonId);
|
|
493
|
+
if (id) formData.append('message[replied_to]', id);
|
|
494
|
+
if (product) formData.append('message[product]', product);
|
|
495
|
+
if (buttonId) formData.append('message[button]', buttonId);
|
|
459
496
|
formData.append('session', Hellotext.session);
|
|
460
497
|
formData.append('locale', Locale.toString());
|
|
461
498
|
this.appendOpeningSequenceMessageIds(formData);
|
|
462
499
|
var element = this.buildMessageElement();
|
|
463
|
-
var attachment = (_cardElement$querySel = cardElement.querySelector('img')) === null || _cardElement$querySel === void 0 ? void 0 : _cardElement$querySel.cloneNode(true);
|
|
500
|
+
var attachment = cardElement === null || cardElement === void 0 ? void 0 : (_cardElement$querySel = cardElement.querySelector('img')) === null || _cardElement$querySel === void 0 ? void 0 : _cardElement$querySel.cloneNode(true);
|
|
464
501
|
element.querySelector('[data-body]').innerText = body;
|
|
465
502
|
if (attachment) {
|
|
466
503
|
var _this$messageAttachme3;
|
|
@@ -484,17 +521,14 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
484
521
|
if (response.failed) {
|
|
485
522
|
// Clear the optimistic typing indicator on failure
|
|
486
523
|
clearTimeout(this.optimisticTypingTimeout);
|
|
487
|
-
this.
|
|
488
|
-
type: 'message:failed',
|
|
489
|
-
id: element.id
|
|
490
|
-
});
|
|
491
|
-
return element.classList.add('failed');
|
|
524
|
+
return this.markMessageFailedFromResponse(response, element);
|
|
492
525
|
}
|
|
493
526
|
var data = yield response.json();
|
|
494
527
|
this.dispatch('set:id', {
|
|
495
528
|
target: element,
|
|
496
529
|
detail: data.id
|
|
497
530
|
});
|
|
531
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), data.created_at || data.createdAt);
|
|
498
532
|
this.clearRevealedOpeningSequenceMessageIds();
|
|
499
533
|
var message = {
|
|
500
534
|
id: data.id,
|
|
@@ -555,14 +589,11 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
555
589
|
var response = yield this.messagesAPI.create(formData);
|
|
556
590
|
if (response.failed) {
|
|
557
591
|
clearTimeout(this.optimisticTypingTimeout);
|
|
558
|
-
this.
|
|
559
|
-
type: 'message:failed',
|
|
560
|
-
id: element.id
|
|
561
|
-
});
|
|
562
|
-
return element.classList.add('failed');
|
|
592
|
+
return this.markMessageFailedFromResponse(response, element);
|
|
563
593
|
}
|
|
564
594
|
var data = yield response.json();
|
|
565
595
|
element.setAttribute('data-id', data.id);
|
|
596
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), data.created_at || data.createdAt);
|
|
566
597
|
this.clearRevealedOpeningSequenceMessageIds();
|
|
567
598
|
Hellotext.eventEmitter.dispatch('webchat:message:sent', {
|
|
568
599
|
id: data.id,
|
|
@@ -664,15 +695,12 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
664
695
|
if (response.failed) {
|
|
665
696
|
// Clear the optimistic typing indicator on failure
|
|
666
697
|
clearTimeout(this.optimisticTypingTimeout);
|
|
667
|
-
this.
|
|
668
|
-
type: 'message:failed',
|
|
669
|
-
id: element.id
|
|
670
|
-
});
|
|
671
|
-
return element.classList.add('failed');
|
|
698
|
+
return this.markMessageFailedFromResponse(response, element);
|
|
672
699
|
}
|
|
673
700
|
var data = yield response.json();
|
|
674
701
|
element.setAttribute('data-id', data.id);
|
|
675
702
|
message.id = data.id;
|
|
703
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), data.created_at || data.createdAt);
|
|
676
704
|
this.clearRevealedOpeningSequenceMessageIds();
|
|
677
705
|
Hellotext.eventEmitter.dispatch('webchat:message:sent', message);
|
|
678
706
|
if (data.conversation !== this.conversationIdValue) {
|
|
@@ -700,8 +728,145 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
700
728
|
element.style.removeProperty('display');
|
|
701
729
|
element.setAttribute('data-controller', 'hellotext--message');
|
|
702
730
|
element.setAttribute('data-hellotext--webchat-target', 'message');
|
|
731
|
+
this.localizeMessageTimestamp(element.querySelector('[data-message-timestamp]'), new Date());
|
|
703
732
|
return element;
|
|
704
733
|
}
|
|
734
|
+
}, {
|
|
735
|
+
key: "focusCompose",
|
|
736
|
+
value: function focusCompose(event) {
|
|
737
|
+
var {
|
|
738
|
+
target
|
|
739
|
+
} = event;
|
|
740
|
+
var ignoredSelector = ['button', 'a', 'input', 'textarea', 'select', 'label', '[role="button"]', 'em-emoji-picker', '[data-hellotext--webchat--emoji-target~="popover"]', '[data-controller~="hellotext--webchat--emoji"]'].join(', ');
|
|
741
|
+
if (!this.hasInputTarget || target.closest(ignoredSelector)) return;
|
|
742
|
+
event.preventDefault();
|
|
743
|
+
this.inputTarget.focus();
|
|
744
|
+
if (typeof this.inputTarget.selectionStart === 'number') {
|
|
745
|
+
var position = this.inputTarget.value.length;
|
|
746
|
+
this.inputTarget.setSelectionRange(position, position);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}, {
|
|
750
|
+
key: "closePopoverFromHeader",
|
|
751
|
+
value: function closePopoverFromHeader(event) {
|
|
752
|
+
var {
|
|
753
|
+
target
|
|
754
|
+
} = event;
|
|
755
|
+
if (target.closest('.hellotext--webchat-header-channel-button, .hellotext--webchat-close-button')) return;
|
|
756
|
+
event.preventDefault();
|
|
757
|
+
this.closePopover();
|
|
758
|
+
}
|
|
759
|
+
}, {
|
|
760
|
+
key: "closePopoverOnEscape",
|
|
761
|
+
value: function closePopoverOnEscape(event) {
|
|
762
|
+
var _this$triggerTarget, _this$triggerTarget$f;
|
|
763
|
+
if (event.key !== 'Escape' || !this.openValue) return;
|
|
764
|
+
event.preventDefault();
|
|
765
|
+
event.stopPropagation();
|
|
766
|
+
this.closePopover();
|
|
767
|
+
(_this$triggerTarget = this.triggerTarget) === null || _this$triggerTarget === void 0 ? void 0 : (_this$triggerTarget$f = _this$triggerTarget.focus) === null || _this$triggerTarget$f === void 0 ? void 0 : _this$triggerTarget$f.call(_this$triggerTarget);
|
|
768
|
+
}
|
|
769
|
+
}, {
|
|
770
|
+
key: "markMessageFailedFromResponse",
|
|
771
|
+
value: function () {
|
|
772
|
+
var _markMessageFailedFromResponse = _asyncToGenerator(function* (response, element) {
|
|
773
|
+
var reason = yield this.messageFailureReason(response);
|
|
774
|
+
this.markMessageFailed(element, reason);
|
|
775
|
+
this.broadcastChannel.postMessage({
|
|
776
|
+
type: 'message:failed',
|
|
777
|
+
id: element.id,
|
|
778
|
+
reason
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
function markMessageFailedFromResponse(_x4, _x5) {
|
|
782
|
+
return _markMessageFailedFromResponse.apply(this, arguments);
|
|
783
|
+
}
|
|
784
|
+
return markMessageFailedFromResponse;
|
|
785
|
+
}()
|
|
786
|
+
}, {
|
|
787
|
+
key: "markMessageFailed",
|
|
788
|
+
value: function markMessageFailed(element, reason) {
|
|
789
|
+
if (!element) return;
|
|
790
|
+
element.classList.add('failed');
|
|
791
|
+
if (!reason) return;
|
|
792
|
+
var timestamp = element.querySelector('[data-message-timestamp]');
|
|
793
|
+
if (timestamp) {
|
|
794
|
+
timestamp.textContent = reason;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}, {
|
|
798
|
+
key: "localizeMessageTimestamps",
|
|
799
|
+
value: function localizeMessageTimestamps() {
|
|
800
|
+
var _root$matches, _root$querySelectorAl;
|
|
801
|
+
var root = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.element;
|
|
802
|
+
if (!root) return;
|
|
803
|
+
var timestamps = (_root$matches = root.matches) !== null && _root$matches !== void 0 && _root$matches.call(root, 'time[datetime][data-message-timestamp]') ? [root] : Array.from(((_root$querySelectorAl = root.querySelectorAll) === null || _root$querySelectorAl === void 0 ? void 0 : _root$querySelectorAl.call(root, 'time[datetime][data-message-timestamp]')) || []);
|
|
804
|
+
timestamps.forEach(timestamp => this.localizeMessageTimestamp(timestamp));
|
|
805
|
+
}
|
|
806
|
+
}, {
|
|
807
|
+
key: "localizeMessageTimestamp",
|
|
808
|
+
value: function localizeMessageTimestamp(timestamp) {
|
|
809
|
+
var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : timestamp === null || timestamp === void 0 ? void 0 : timestamp.getAttribute('datetime');
|
|
810
|
+
if (!timestamp || !value) return;
|
|
811
|
+
var date = value instanceof Date ? value : new Date(value);
|
|
812
|
+
if (Number.isNaN(date.getTime())) return;
|
|
813
|
+
timestamp.setAttribute('datetime', date.toISOString());
|
|
814
|
+
timestamp.textContent = this.formatMessageTimestamp(date);
|
|
815
|
+
}
|
|
816
|
+
}, {
|
|
817
|
+
key: "formatMessageTimestamp",
|
|
818
|
+
value: function formatMessageTimestamp(date) {
|
|
819
|
+
return this.constructor.messageTimestampFormatterFor(Locale.toString()).format(date);
|
|
820
|
+
}
|
|
821
|
+
}, {
|
|
822
|
+
key: "messageFailureReason",
|
|
823
|
+
value: function () {
|
|
824
|
+
var _messageFailureReason = _asyncToGenerator(function* (response) {
|
|
825
|
+
var nativeResponse = (response === null || response === void 0 ? void 0 : response.data) || (response === null || response === void 0 ? void 0 : response.response);
|
|
826
|
+
var fallback = (nativeResponse === null || nativeResponse === void 0 ? void 0 : nativeResponse.statusText) || 'Message failed';
|
|
827
|
+
try {
|
|
828
|
+
var _jsonResponse$json;
|
|
829
|
+
var jsonResponse = nativeResponse !== null && nativeResponse !== void 0 && nativeResponse.clone ? nativeResponse.clone() : nativeResponse;
|
|
830
|
+
var payload = yield jsonResponse === null || jsonResponse === void 0 ? void 0 : (_jsonResponse$json = jsonResponse.json) === null || _jsonResponse$json === void 0 ? void 0 : _jsonResponse$json.call(jsonResponse);
|
|
831
|
+
var reason = this.messageFailureReasonFromPayload(payload);
|
|
832
|
+
if (reason) return reason;
|
|
833
|
+
} catch (_) {
|
|
834
|
+
// Fall through to text parsing/fallback. Some stores strip content-type or
|
|
835
|
+
// return non-JSON failures, so the timestamp still needs a useful reason.
|
|
836
|
+
}
|
|
837
|
+
try {
|
|
838
|
+
var _textResponse$text;
|
|
839
|
+
var textResponse = nativeResponse !== null && nativeResponse !== void 0 && nativeResponse.clone ? nativeResponse.clone() : nativeResponse;
|
|
840
|
+
var text = yield textResponse === null || textResponse === void 0 ? void 0 : (_textResponse$text = textResponse.text) === null || _textResponse$text === void 0 ? void 0 : _textResponse$text.call(textResponse);
|
|
841
|
+
return this.messageFailureReasonFromText(text) || fallback;
|
|
842
|
+
} catch (_) {
|
|
843
|
+
return fallback;
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
function messageFailureReason(_x6) {
|
|
847
|
+
return _messageFailureReason.apply(this, arguments);
|
|
848
|
+
}
|
|
849
|
+
return messageFailureReason;
|
|
850
|
+
}()
|
|
851
|
+
}, {
|
|
852
|
+
key: "messageFailureReasonFromText",
|
|
853
|
+
value: function messageFailureReasonFromText(text) {
|
|
854
|
+
if (typeof text !== 'string') return null;
|
|
855
|
+
var value = text.trim();
|
|
856
|
+
if (!value || value.startsWith('<')) return null;
|
|
857
|
+
try {
|
|
858
|
+
return this.messageFailureReasonFromPayload(JSON.parse(value)) || value;
|
|
859
|
+
} catch (_) {
|
|
860
|
+
return value;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}, {
|
|
864
|
+
key: "messageFailureReasonFromPayload",
|
|
865
|
+
value: function messageFailureReasonFromPayload(payload) {
|
|
866
|
+
var _payload$error, _payload$errors, _payload$errors2, _payload$errors2$, _payload$errors3, _payload$errors3$;
|
|
867
|
+
if (!payload) return null;
|
|
868
|
+
return [(_payload$error = payload.error) === null || _payload$error === void 0 ? void 0 : _payload$error.message, payload.message, (_payload$errors = payload.errors) === null || _payload$errors === void 0 ? void 0 : _payload$errors.message, (_payload$errors2 = payload.errors) === null || _payload$errors2 === void 0 ? void 0 : (_payload$errors2$ = _payload$errors2[0]) === null || _payload$errors2$ === void 0 ? void 0 : _payload$errors2$.message, (_payload$errors3 = payload.errors) === null || _payload$errors3 === void 0 ? void 0 : (_payload$errors3$ = _payload$errors3[0]) === null || _payload$errors3$ === void 0 ? void 0 : _payload$errors3$.description].find(reason => typeof reason === 'string' && reason.trim().length > 0);
|
|
869
|
+
}
|
|
705
870
|
}, {
|
|
706
871
|
key: "messageAttachmentsContainer",
|
|
707
872
|
value: function messageAttachmentsContainer(element) {
|
|
@@ -832,9 +997,28 @@ var _default = /*#__PURE__*/function (_Controller) {
|
|
|
832
997
|
get: function get() {
|
|
833
998
|
return window.matchMedia("(max-width: ".concat(this.fullScreenThresholdValue, "px)")).matches;
|
|
834
999
|
}
|
|
1000
|
+
}], [{
|
|
1001
|
+
key: "messageTimestampFormatterFor",
|
|
1002
|
+
value: function messageTimestampFormatterFor(locale) {
|
|
1003
|
+
var key = locale || 'default';
|
|
1004
|
+
if (!this.messageTimestampFormatters[key]) {
|
|
1005
|
+
this.messageTimestampFormatters[key] = this.buildMessageTimestampFormatter(locale);
|
|
1006
|
+
}
|
|
1007
|
+
return this.messageTimestampFormatters[key];
|
|
1008
|
+
}
|
|
1009
|
+
}, {
|
|
1010
|
+
key: "buildMessageTimestampFormatter",
|
|
1011
|
+
value: function buildMessageTimestampFormatter(locale) {
|
|
1012
|
+
try {
|
|
1013
|
+
return new Intl.DateTimeFormat(locale || undefined, MESSAGE_TIMESTAMP_FORMAT_OPTIONS);
|
|
1014
|
+
} catch (_) {
|
|
1015
|
+
return new Intl.DateTimeFormat(undefined, MESSAGE_TIMESTAMP_FORMAT_OPTIONS);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
835
1018
|
}]);
|
|
836
1019
|
return _default;
|
|
837
1020
|
}(Controller);
|
|
1021
|
+
_default.messageTimestampFormatters = {};
|
|
838
1022
|
_default.values = {
|
|
839
1023
|
id: String,
|
|
840
1024
|
conversationId: String,
|
|
@@ -39,6 +39,7 @@ let Configuration = /*#__PURE__*/function () {
|
|
|
39
39
|
*/
|
|
40
40
|
function assign(props) {
|
|
41
41
|
if (props) {
|
|
42
|
+
const shouldInferActionCableUrl = Object.prototype.hasOwnProperty.call(props, 'apiRoot') && !Object.prototype.hasOwnProperty.call(props, 'actionCableUrl');
|
|
42
43
|
Object.entries(props).forEach(([key, value]) => {
|
|
43
44
|
if (key === 'forms') {
|
|
44
45
|
this.forms = _forms.Forms.assign(value);
|
|
@@ -48,6 +49,9 @@ let Configuration = /*#__PURE__*/function () {
|
|
|
48
49
|
this[key] = value;
|
|
49
50
|
}
|
|
50
51
|
});
|
|
52
|
+
if (shouldInferActionCableUrl) {
|
|
53
|
+
this.actionCableUrl = this.actionCableUrlForApiRoot(this.apiRoot);
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
return this;
|
|
53
57
|
}
|
|
@@ -64,6 +68,21 @@ let Configuration = /*#__PURE__*/function () {
|
|
|
64
68
|
value: function endpoint(path) {
|
|
65
69
|
return `${this.apiRoot}/${path}`;
|
|
66
70
|
}
|
|
71
|
+
}, {
|
|
72
|
+
key: "actionCableUrlForApiRoot",
|
|
73
|
+
value: function actionCableUrlForApiRoot(apiRoot) {
|
|
74
|
+
try {
|
|
75
|
+
const url = new URL(apiRoot);
|
|
76
|
+
const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
77
|
+
url.protocol = protocol;
|
|
78
|
+
url.pathname = '/cable';
|
|
79
|
+
url.search = '';
|
|
80
|
+
url.hash = '';
|
|
81
|
+
return url.toString();
|
|
82
|
+
} catch (_) {
|
|
83
|
+
return this.actionCableUrl;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
67
86
|
}]);
|
|
68
87
|
return Configuration;
|
|
69
88
|
}();
|
|
@@ -34,6 +34,7 @@ var Configuration = /*#__PURE__*/function () {
|
|
|
34
34
|
*/
|
|
35
35
|
function assign(props) {
|
|
36
36
|
if (props) {
|
|
37
|
+
var shouldInferActionCableUrl = Object.prototype.hasOwnProperty.call(props, 'apiRoot') && !Object.prototype.hasOwnProperty.call(props, 'actionCableUrl');
|
|
37
38
|
Object.entries(props).forEach(_ref => {
|
|
38
39
|
var [key, value] = _ref;
|
|
39
40
|
if (key === 'forms') {
|
|
@@ -44,6 +45,9 @@ var Configuration = /*#__PURE__*/function () {
|
|
|
44
45
|
this[key] = value;
|
|
45
46
|
}
|
|
46
47
|
});
|
|
48
|
+
if (shouldInferActionCableUrl) {
|
|
49
|
+
this.actionCableUrl = this.actionCableUrlForApiRoot(this.apiRoot);
|
|
50
|
+
}
|
|
47
51
|
}
|
|
48
52
|
return this;
|
|
49
53
|
}
|
|
@@ -60,6 +64,21 @@ var Configuration = /*#__PURE__*/function () {
|
|
|
60
64
|
value: function endpoint(path) {
|
|
61
65
|
return "".concat(this.apiRoot, "/").concat(path);
|
|
62
66
|
}
|
|
67
|
+
}, {
|
|
68
|
+
key: "actionCableUrlForApiRoot",
|
|
69
|
+
value: function actionCableUrlForApiRoot(apiRoot) {
|
|
70
|
+
try {
|
|
71
|
+
var url = new URL(apiRoot);
|
|
72
|
+
var protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
73
|
+
url.protocol = protocol;
|
|
74
|
+
url.pathname = '/cable';
|
|
75
|
+
url.search = '';
|
|
76
|
+
url.hash = '';
|
|
77
|
+
return url.toString();
|
|
78
|
+
} catch (_) {
|
|
79
|
+
return this.actionCableUrl;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
63
82
|
}]);
|
|
64
83
|
return Configuration;
|
|
65
84
|
}();
|
package/lib/models/business.cjs
CHANGED
|
@@ -12,17 +12,22 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
|
|
|
12
12
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
13
13
|
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
14
14
|
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); }
|
|
15
|
+
const stylesheetAttribute = 'data-hellotext-stylesheet';
|
|
16
|
+
const stylesheetLoadTimeout = 10000;
|
|
17
|
+
|
|
15
18
|
/**
|
|
16
19
|
* @typedef {Object} BusinessCountry
|
|
17
20
|
* @property {String} [code] - ISO country code configured for the business.
|
|
18
21
|
* @property {String} [prefix] - Phone country prefix configured for the business.
|
|
19
22
|
*/
|
|
23
|
+
|
|
20
24
|
/**
|
|
21
25
|
* @typedef {Object} BusinessWebchat
|
|
22
26
|
* @property {String} [id] - Dashboard webchat id configured for the business.
|
|
23
27
|
* @property {Object} [appearance] - Dashboard appearance defaults for the webchat.
|
|
24
28
|
* @property {Object} [whatsapp] - Dashboard WhatsApp handoff defaults for the webchat.
|
|
25
29
|
*/
|
|
30
|
+
|
|
26
31
|
/**
|
|
27
32
|
* Public business metadata returned by `public/businesses/:id`.
|
|
28
33
|
*
|
|
@@ -36,6 +41,7 @@ function _toPrimitive(input, hint) { if (typeof input !== "object" || input ===
|
|
|
36
41
|
* @property {String|Array<String>} [whitelist] - Domain whitelist configuration.
|
|
37
42
|
* @property {String} [subscription] - Current business subscription tier.
|
|
38
43
|
*/
|
|
44
|
+
|
|
39
45
|
/**
|
|
40
46
|
* Public business context used by the SDK for tracking, forms, and webchat defaults.
|
|
41
47
|
*/
|
|
@@ -47,6 +53,8 @@ let Business = /*#__PURE__*/function () {
|
|
|
47
53
|
_classCallCheck(this, Business);
|
|
48
54
|
this.id = id;
|
|
49
55
|
this.data = null;
|
|
56
|
+
this.stylesheet = null;
|
|
57
|
+
this.stylesheetLoaded = Promise.resolve(false);
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
/**
|
|
@@ -87,11 +95,12 @@ let Business = /*#__PURE__*/function () {
|
|
|
87
95
|
key: "setData",
|
|
88
96
|
value: function setData(data) {
|
|
89
97
|
this.data = data;
|
|
90
|
-
if (typeof document !== 'undefined') {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
if (typeof document !== 'undefined' && data.style_url) {
|
|
99
|
+
this.stylesheet = this.constructor.ensureStylesheet(data.style_url);
|
|
100
|
+
this.stylesheetLoaded = this.constructor.waitForStylesheet(this.stylesheet);
|
|
101
|
+
} else {
|
|
102
|
+
this.stylesheet = null;
|
|
103
|
+
this.stylesheetLoaded = Promise.resolve(false);
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
}, {
|
|
@@ -135,6 +144,78 @@ let Business = /*#__PURE__*/function () {
|
|
|
135
144
|
get: function () {
|
|
136
145
|
return this.data.features;
|
|
137
146
|
}
|
|
147
|
+
}], [{
|
|
148
|
+
key: "stylesheetSelector",
|
|
149
|
+
get: function () {
|
|
150
|
+
return `link[rel="stylesheet"][${stylesheetAttribute}]`;
|
|
151
|
+
}
|
|
152
|
+
}, {
|
|
153
|
+
key: "ensureStylesheet",
|
|
154
|
+
value: function ensureStylesheet(styleUrl) {
|
|
155
|
+
const href = this.normalizedStylesheetUrl(styleUrl);
|
|
156
|
+
const existingLink = this.stylesheetLinks.find(link => link.href === href);
|
|
157
|
+
if (existingLink) {
|
|
158
|
+
existingLink.setAttribute(stylesheetAttribute, 'true');
|
|
159
|
+
return existingLink;
|
|
160
|
+
}
|
|
161
|
+
const linkTag = document.createElement('link');
|
|
162
|
+
linkTag.rel = 'stylesheet';
|
|
163
|
+
linkTag.href = styleUrl;
|
|
164
|
+
linkTag.setAttribute(stylesheetAttribute, 'true');
|
|
165
|
+
this.waitForStylesheet(linkTag);
|
|
166
|
+
document.head.append(linkTag);
|
|
167
|
+
return linkTag;
|
|
168
|
+
}
|
|
169
|
+
}, {
|
|
170
|
+
key: "stylesheetLinks",
|
|
171
|
+
get: function () {
|
|
172
|
+
if (typeof document === 'undefined') return [];
|
|
173
|
+
return Array.from(document.querySelectorAll(this.stylesheetSelector));
|
|
174
|
+
}
|
|
175
|
+
}, {
|
|
176
|
+
key: "latestStylesheet",
|
|
177
|
+
get: function () {
|
|
178
|
+
return this.stylesheetLinks[this.stylesheetLinks.length - 1];
|
|
179
|
+
}
|
|
180
|
+
}, {
|
|
181
|
+
key: "normalizedStylesheetUrl",
|
|
182
|
+
value: function normalizedStylesheetUrl(styleUrl) {
|
|
183
|
+
try {
|
|
184
|
+
return new URL(styleUrl, document.baseURI).href;
|
|
185
|
+
} catch (_error) {
|
|
186
|
+
return styleUrl;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}, {
|
|
190
|
+
key: "waitForStylesheet",
|
|
191
|
+
value: function waitForStylesheet(linkTag) {
|
|
192
|
+
if (!linkTag) return Promise.resolve(false);
|
|
193
|
+
if (this.stylesheetIsLoaded(linkTag)) return Promise.resolve(true);
|
|
194
|
+
if (linkTag.dataset.hellotextStylesheetLoaded === 'false') return Promise.resolve(false);
|
|
195
|
+
if (linkTag._hellotextStylesheetLoaded) return linkTag._hellotextStylesheetLoaded;
|
|
196
|
+
linkTag._hellotextStylesheetLoaded = new Promise(resolve => {
|
|
197
|
+
let timeout;
|
|
198
|
+
const finish = loaded => {
|
|
199
|
+
clearTimeout(timeout);
|
|
200
|
+
linkTag.removeEventListener('load', handleLoad);
|
|
201
|
+
linkTag.removeEventListener('error', handleError);
|
|
202
|
+
linkTag.dataset.hellotextStylesheetLoaded = loaded ? 'true' : 'false';
|
|
203
|
+
resolve(loaded);
|
|
204
|
+
};
|
|
205
|
+
const handleLoad = () => finish(this.stylesheetIsLoaded(linkTag));
|
|
206
|
+
const handleError = () => finish(false);
|
|
207
|
+
linkTag.addEventListener('load', handleLoad);
|
|
208
|
+
linkTag.addEventListener('error', handleError);
|
|
209
|
+
timeout = setTimeout(() => finish(this.stylesheetIsLoaded(linkTag)), stylesheetLoadTimeout);
|
|
210
|
+
if (timeout.unref) timeout.unref();
|
|
211
|
+
});
|
|
212
|
+
return linkTag._hellotextStylesheetLoaded;
|
|
213
|
+
}
|
|
214
|
+
}, {
|
|
215
|
+
key: "stylesheetIsLoaded",
|
|
216
|
+
value: function stylesheetIsLoaded(linkTag) {
|
|
217
|
+
return linkTag.dataset.hellotextStylesheetLoaded === 'true' || !!linkTag.sheet;
|
|
218
|
+
}
|
|
138
219
|
}]);
|
|
139
220
|
return Business;
|
|
140
221
|
}();
|