yelda-webchat 1.1.9 → 1.1.13
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/README.md +16 -15
- package/dist/css/yeldaWebchatInjector.css +20 -22
- package/dist/css/yeldaWebchatInjector.min.css +7 -7
- package/dist/css/yeldaWebchatInjector.min.css.map +1 -1
- package/dist/js/yeldaWebchatInjector.js +109 -21
- package/dist/js/yeldaWebchatInjector.js.map +1 -1
- package/dist/js/yeldaWebchatInjector.min.js +1 -1
- package/package.json +1 -1
- package/src/config/index.js +6 -0
- package/src/css/yeldaWebchatInjector.css +20 -22
- package/src/js/yeldaWebchatInjector.js +83 -13
package/package.json
CHANGED
package/src/config/index.js
CHANGED
|
@@ -30,5 +30,11 @@ module.exports = {
|
|
|
30
30
|
ADD_BUBBLE_TEXT: 'addBubbleText',
|
|
31
31
|
ADD_MINIMAL_NOTIFICATION_TEXT: 'addMinimalNotificationText'
|
|
32
32
|
}
|
|
33
|
+
},
|
|
34
|
+
CHAT_BUBBLE_EXTERNAL_ENDPOINT: 'https://webchat.yelda.ai/webchat',
|
|
35
|
+
CHAT_BUBBLE_REQUEST_TIMEOUT: 5000,
|
|
36
|
+
APP_ENV_VALUES: {
|
|
37
|
+
STAGING: 'staging',
|
|
38
|
+
PRODUCTION: 'production'
|
|
33
39
|
}
|
|
34
40
|
}
|
|
@@ -3,33 +3,26 @@
|
|
|
3
3
|
|
|
4
4
|
.yelda_assistant_img {
|
|
5
5
|
cursor: pointer;
|
|
6
|
-
opacity: 1;
|
|
7
6
|
height: auto;
|
|
8
|
-
transition
|
|
9
|
-
transition-duration: 1s, 1ms;
|
|
10
|
-
transition-delay: 1.2s, 1.2s;
|
|
7
|
+
transition: opacity 0.6s ease-in-out 1.2s, height 1ms linear 1.2s;
|
|
11
8
|
animation-name: appear;
|
|
12
9
|
animation-duration: 0.8s;
|
|
13
10
|
animation-delay: 1s;
|
|
14
11
|
animation-timing-function: cubic-bezier(0.230, 1.000, 0.320, 1.000);
|
|
15
12
|
animation-iteration-count: 1;
|
|
16
|
-
animation-fill-mode:
|
|
13
|
+
animation-fill-mode: both;
|
|
17
14
|
opacity: 0;
|
|
18
15
|
overflow: hidden;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
.yelda_container.y_active .yelda_assistant_img{
|
|
22
|
-
|
|
23
|
-
height: 0;
|
|
24
|
-
transition-property: opacity, height;
|
|
25
|
-
transition-duration: 1ms, 1ms;
|
|
26
|
-
transition-delay: 0, 0;
|
|
19
|
+
display:none;
|
|
27
20
|
animation: none;
|
|
28
21
|
}
|
|
29
22
|
|
|
23
|
+
/* activated : not the first time we see the bubble */
|
|
30
24
|
.yelda_assistant_img.activated{
|
|
31
|
-
transition
|
|
32
|
-
/*animation-delay: 0s;*/
|
|
25
|
+
transition: opacity 0.6s ease-in-out 0.6s, height 1ms linear 0.6s;
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
.yelda_assistant_img.default {
|
|
@@ -65,6 +58,9 @@
|
|
|
65
58
|
font-size: 35px !important;
|
|
66
59
|
}
|
|
67
60
|
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
68
64
|
.yelda_container {
|
|
69
65
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
|
|
70
66
|
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
|
@@ -93,14 +89,12 @@
|
|
|
93
89
|
}
|
|
94
90
|
|
|
95
91
|
.yelda_iframe_container {
|
|
96
|
-
width:
|
|
92
|
+
width: 0;
|
|
97
93
|
height: 0;
|
|
98
94
|
max-height: 600px;
|
|
99
95
|
margin: 0;
|
|
100
96
|
overflow: hidden;
|
|
101
|
-
transition
|
|
102
|
-
transition-duration: 1s, 1s, 1ms;
|
|
103
|
-
transition-delay: 0s, 0s, 1s;
|
|
97
|
+
transition: opacity 0.6s linear 0s, transform 0.6s ease-in-out 0s, height 1ms linear 0.6s, width 1ms linear 0.6s;
|
|
104
98
|
opacity: 0;
|
|
105
99
|
transform: translateY(20px);
|
|
106
100
|
}
|
|
@@ -111,10 +105,9 @@
|
|
|
111
105
|
}
|
|
112
106
|
|
|
113
107
|
.y_active .yelda_iframe_container{
|
|
108
|
+
width: 430px;
|
|
114
109
|
height: calc(100vh - 170px);
|
|
115
|
-
transition
|
|
116
|
-
transition-duration: 1s, 1s, 1ms;
|
|
117
|
-
transition-delay: 0s, 0s, 0s;
|
|
110
|
+
transition: opacity 0.6s linear 0s, transform 0.6s ease-in-out 0s, height 1ms linear 0s, width 1ms linear 0s;
|
|
118
111
|
opacity: 1 !important;
|
|
119
112
|
transform: translateY(0);
|
|
120
113
|
}
|
|
@@ -142,13 +135,17 @@
|
|
|
142
135
|
z-index: 2147483647;
|
|
143
136
|
}
|
|
144
137
|
|
|
138
|
+
.y_active .yelda_iframe_container{
|
|
139
|
+
width: 100% !important;
|
|
140
|
+
}
|
|
141
|
+
|
|
145
142
|
.yelda_iframe_container:not(.inner) {
|
|
146
143
|
position: fixed;
|
|
147
144
|
left: 0;
|
|
148
145
|
top: 0;
|
|
149
146
|
right: 0;
|
|
150
147
|
bottom: 0;
|
|
151
|
-
width:
|
|
148
|
+
width: 0;
|
|
152
149
|
height: auto;
|
|
153
150
|
max-height: none;
|
|
154
151
|
border-radius: 0;
|
|
@@ -156,6 +153,8 @@
|
|
|
156
153
|
padding: 0;
|
|
157
154
|
}
|
|
158
155
|
|
|
156
|
+
|
|
157
|
+
|
|
159
158
|
.yelda_iframe_container.inner {
|
|
160
159
|
width: 100%;
|
|
161
160
|
box-shadow: 0 5px 32px rgba(0,0,0,.16);
|
|
@@ -177,8 +176,6 @@
|
|
|
177
176
|
box-shadow: #00000030 0 2px 8px 0;
|
|
178
177
|
background-color: white;
|
|
179
178
|
cursor: pointer;
|
|
180
|
-
right: 0;
|
|
181
|
-
bottom: 76px;
|
|
182
179
|
max-width: 300px;
|
|
183
180
|
text-align: left;
|
|
184
181
|
font-size: 14px;
|
|
@@ -260,3 +257,4 @@ a.bubbleCloseButton:hover {
|
|
|
260
257
|
opacity: 1;
|
|
261
258
|
}
|
|
262
259
|
}
|
|
260
|
+
|
|
@@ -282,15 +282,15 @@ class YeldaChat {
|
|
|
282
282
|
/**
|
|
283
283
|
* Add 'y_active' class to the webChatContainer if required
|
|
284
284
|
*
|
|
285
|
-
* To control the opacity of the iframe container (.yelda_iframe_container) and the assistant image (.yelda_assistant_img),
|
|
285
|
+
* To control the opacity/display of the iframe container (.yelda_iframe_container) and the assistant image (.yelda_assistant_img),
|
|
286
286
|
* We add and remove the "y_active" CSS class to the webChatContainer (.yelda_container) which is always visible
|
|
287
287
|
* By default
|
|
288
|
-
* - yelda_iframe_container is hidden (opacity: 0;)
|
|
289
|
-
* - assistant image is
|
|
288
|
+
* - yelda_iframe_container is hidden (opacity: 0; height:0; width: 0; to not affect page interactions)
|
|
289
|
+
* - assistant image is hidden (opacity: 0), but immediatly animated by css to be displayed (opacity: 1 with animation-name: appear;) for yelda_assistant_img)
|
|
290
290
|
*
|
|
291
291
|
* When we add the class "y_active" to (webChatContainer)
|
|
292
292
|
* - yelda_iframe_container is now visible (.y_active .yelda_iframe_container => opacity: 1)
|
|
293
|
-
* - the assistant image is hidden (.yelda_container.y_active .yelda_assistant_img =>
|
|
293
|
+
* - the assistant image is hidden (.yelda_container.y_active .yelda_assistant_img => display:none, no opacity manipulation because no need of animation)
|
|
294
294
|
*
|
|
295
295
|
* @param {Boolean} data.shouldBeOpened
|
|
296
296
|
* @param {Boolean} data.isStartBtn
|
|
@@ -775,38 +775,108 @@ class YeldaChat {
|
|
|
775
775
|
return isFound
|
|
776
776
|
}
|
|
777
777
|
|
|
778
|
+
/**
|
|
779
|
+
* Get the app env from the assistant url
|
|
780
|
+
* @param {String} assistantUrl
|
|
781
|
+
* @returns {String} env
|
|
782
|
+
*/
|
|
783
|
+
getAppEnv(assistantUrl) {
|
|
784
|
+
if (config.REGEX_HOST.STAGING.test(assistantUrl)) {
|
|
785
|
+
return config.APP_ENV_VALUES.STAGING
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// By default, use the production env
|
|
789
|
+
return config.APP_ENV_VALUES.PRODUCTION
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Get the chat bubble url base based on isFallback
|
|
794
|
+
* @param {Object} data { assistantUrl, assistantId, settingId }
|
|
795
|
+
* @param {Boolean} isFallback fallback means yelda endpoint
|
|
796
|
+
* @returns {String} url base
|
|
797
|
+
*/
|
|
798
|
+
getChatBubbleUrlBase(data, isFallback) {
|
|
799
|
+
if (isFallback) {
|
|
800
|
+
return `${data.assistantUrl}/assistants`
|
|
801
|
+
}
|
|
802
|
+
return config.CHAT_BUBBLE_EXTERNAL_ENDPOINT
|
|
803
|
+
}
|
|
804
|
+
|
|
778
805
|
/**
|
|
779
806
|
* return getAssistantSettings endpoint URL from data
|
|
780
807
|
* @param {Object} data { assistantUrl, assistantId, settingId }
|
|
808
|
+
* @param {Boolean} isFallback
|
|
781
809
|
* @return {String} url
|
|
782
810
|
*/
|
|
783
|
-
getAssistantSettingsUrl(data) {
|
|
811
|
+
getAssistantSettingsUrl(data, isFallback) {
|
|
812
|
+
const urlBase = this.getChatBubbleUrlBase(data, isFallback)
|
|
813
|
+
// The app env is required as query for the external chatbubble endpoint
|
|
814
|
+
// If the env was not explicitly set in data, guess it from the assistant url
|
|
815
|
+
const appEnv = data.env || this.getAppEnv(data.assistantUrl)
|
|
816
|
+
const envQuery = `env=${appEnv}`
|
|
784
817
|
if(data.settingId) {
|
|
785
|
-
return `${
|
|
818
|
+
return `${urlBase}/settings/${data.settingId}/chatBubble?${envQuery}`
|
|
786
819
|
}
|
|
787
820
|
|
|
788
|
-
return `${
|
|
821
|
+
return `${urlBase}/${data.assistantId}/chatBubble/${data.locale}?${envQuery}`
|
|
789
822
|
}
|
|
790
823
|
|
|
791
824
|
/**
|
|
792
825
|
* Update assistantImage with assistant settings from backend if any
|
|
793
826
|
* @param {Object} data { assistantUrl, assistantId, settingId }
|
|
827
|
+
* @param {Object} options
|
|
828
|
+
* @param {Object} options.isFallback
|
|
829
|
+
* @param {Number} options.customTimeout in milliseconds
|
|
794
830
|
* @return {Promise}
|
|
795
831
|
*/
|
|
796
|
-
getAssistantSettings(data) {
|
|
832
|
+
getAssistantSettings(data, { isFallback = false, customTimeout = null } = {}) {
|
|
797
833
|
return new Promise((resolve, reject) => {
|
|
798
834
|
try {
|
|
799
835
|
const xhr = new XMLHttpRequest()
|
|
800
|
-
const url = this.getAssistantSettingsUrl(data)
|
|
801
836
|
|
|
837
|
+
// Get the url base depending on if we are doing the basic request (external chatbubble endpoint)
|
|
838
|
+
// or the fallback one (chatbubble endpoint in Yelda)
|
|
839
|
+
const url = this.getAssistantSettingsUrl(data, isFallback)
|
|
840
|
+
|
|
802
841
|
xhr.open('GET', url)
|
|
842
|
+
if (customTimeout) {
|
|
843
|
+
xhr.timeout = customTimeout
|
|
844
|
+
}
|
|
803
845
|
xhr.send()
|
|
804
846
|
|
|
805
847
|
// Bind and call are necessary to pass the "this" to the callback function
|
|
806
|
-
xhr.onreadystatechange =
|
|
848
|
+
xhr.onreadystatechange = () => {
|
|
807
849
|
if (xhr.readyState === 4) {
|
|
808
|
-
const
|
|
809
|
-
|
|
850
|
+
const responseText = xhr.responseText ? JSON.parse(xhr.responseText) : null
|
|
851
|
+
// Yelda endpoint returns { data: ...webchatSettings } (to be compatible with old versions of the chat-plugin)
|
|
852
|
+
// whereas the external endpoint returns { ...webchatSettings }
|
|
853
|
+
// We need to handle both format
|
|
854
|
+
const webchatSettings = responseText && (responseText.data || responseText)
|
|
855
|
+
|
|
856
|
+
if (webchatSettings) {
|
|
857
|
+
return resolve(webchatSettings)
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// We did not received the expected webchatSettings
|
|
861
|
+
// If we are already in fallback mode, it means there is no webchat settings for the given init information
|
|
862
|
+
if (isFallback) {
|
|
863
|
+
return resolve(null)
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// If the initial request do not return webchatSettings, it might be because they were not set in Redis yet
|
|
867
|
+
// So let's call the yelda endpoint (fallback) that will find the setting (if it exists) and set it in Redis
|
|
868
|
+
return resolve(this.getAssistantSettings(data, { isFallback: true }))
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
xhr.ontimeout = () => {
|
|
873
|
+
/*
|
|
874
|
+
It the initial request to the external chatbubble endpoint timed out, (maybe the endpoint is down)
|
|
875
|
+
let's fallback on the yelda endpoint
|
|
876
|
+
*/
|
|
877
|
+
if (!isFallback) {
|
|
878
|
+
// Set isFallback to true to be sure to not end up in an infinite loop
|
|
879
|
+
return resolve(this.getAssistantSettings(data, { isFallback: true }))
|
|
810
880
|
}
|
|
811
881
|
}
|
|
812
882
|
} catch (e) {
|
|
@@ -846,7 +916,7 @@ class YeldaChat {
|
|
|
846
916
|
|
|
847
917
|
// Get assistant settings from backend
|
|
848
918
|
try {
|
|
849
|
-
this.webchatSettings = await this.getAssistantSettings(data)
|
|
919
|
+
this.webchatSettings = await this.getAssistantSettings(data, { customTimeout: config.CHAT_BUBBLE_REQUEST_TIMEOUT })
|
|
850
920
|
// Webchat can be loaded thanks to a single settingId or group of data : {assistantId, assistantSlug, locale}
|
|
851
921
|
// If only settingId is provided, then we will fill {assistantId, assistantSlug, locale} thanks to the assistant settings
|
|
852
922
|
data = this.updateAssistantData(data, this.webchatSettings)
|