@hellotext/hellotext 2.1.1 → 2.1.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/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/controllers/webchat/emoji_picker_controller.cjs +6 -6
- package/lib/controllers/webchat/emoji_picker_controller.js +5 -14
- package/lib/controllers/webchat_controller.cjs +63 -15
- package/lib/controllers/webchat_controller.js +63 -15
- package/lib/core/configuration/locale.cjs +87 -0
- package/lib/core/configuration/locale.js +81 -0
- package/lib/core/configuration.cjs +10 -0
- package/lib/core/configuration.js +10 -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/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/controllers/webchat/emoji_picker_controller.js +9 -15
- package/src/controllers/webchat_controller.js +69 -19
- package/src/core/configuration/locale.js +50 -0
- package/src/core/configuration.js +10 -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
|
@@ -5,6 +5,7 @@ import WebchatMessagesAPI from '../api/webchat/messages'
|
|
|
5
5
|
import WebchatChannel from '../channels/webchat_channel'
|
|
6
6
|
import Hellotext from '../hellotext'
|
|
7
7
|
|
|
8
|
+
import { Locale } from '../core'
|
|
8
9
|
import { Webchat as WebchatConfiguration, behaviors } from '../core/configuration/webchat'
|
|
9
10
|
|
|
10
11
|
import { LogoBuilder } from '../builders/logo_builder'
|
|
@@ -21,8 +22,11 @@ export default class extends Controller {
|
|
|
21
22
|
autoPlacement: { type: Boolean, default: false },
|
|
22
23
|
disabled: { type: Boolean, default: false },
|
|
23
24
|
nextPage: { type: Number, default: undefined },
|
|
25
|
+
fullScreenThreshold: { type: Number, default: 1024 },
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
static classes = ['fadeOut']
|
|
29
|
+
|
|
26
30
|
static targets = [
|
|
27
31
|
'trigger',
|
|
28
32
|
'popover',
|
|
@@ -88,7 +92,7 @@ export default class extends Controller {
|
|
|
88
92
|
this.toolbarTarget.appendChild(LogoBuilder.build())
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
if (
|
|
95
|
+
if (this.shouldOpenOnMount) {
|
|
92
96
|
this.openValue = true
|
|
93
97
|
}
|
|
94
98
|
|
|
@@ -205,20 +209,31 @@ export default class extends Controller {
|
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
|
|
212
|
+
closePopover() {
|
|
213
|
+
this.popoverTarget.classList.add(...this.fadeOutClasses)
|
|
214
|
+
|
|
215
|
+
setTimeout(() => {
|
|
216
|
+
this.openValue = false
|
|
217
|
+
}, 250)
|
|
218
|
+
}
|
|
219
|
+
|
|
208
220
|
onPopoverOpened() {
|
|
209
|
-
this.
|
|
221
|
+
if (!this.onMobile) {
|
|
222
|
+
this.inputTarget.focus()
|
|
223
|
+
}
|
|
210
224
|
|
|
211
225
|
if (!this.scrolled) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
226
|
+
requestAnimationFrame(() => {
|
|
227
|
+
this.messagesContainerTarget.scroll({
|
|
228
|
+
top: this.messagesContainerTarget.scrollHeight,
|
|
229
|
+
behavior: 'instant',
|
|
230
|
+
})
|
|
215
231
|
})
|
|
216
232
|
|
|
217
233
|
this.scrolled = true
|
|
218
234
|
}
|
|
219
235
|
|
|
220
236
|
Hellotext.eventEmitter.dispatch('webchat:opened')
|
|
221
|
-
|
|
222
237
|
localStorage.setItem(`hellotext--webchat--${this.idValue}`, 'opened')
|
|
223
238
|
|
|
224
239
|
if (this.unreadCounterTarget.style.display === 'none') return
|
|
@@ -231,11 +246,6 @@ export default class extends Controller {
|
|
|
231
246
|
|
|
232
247
|
onPopoverClosed() {
|
|
233
248
|
Hellotext.eventEmitter.dispatch('webchat:closed')
|
|
234
|
-
|
|
235
|
-
setTimeout(() => {
|
|
236
|
-
this.inputTarget.value = ''
|
|
237
|
-
})
|
|
238
|
-
|
|
239
249
|
localStorage.setItem(`hellotext--webchat--${this.idValue}`, 'closed')
|
|
240
250
|
}
|
|
241
251
|
|
|
@@ -264,7 +274,7 @@ export default class extends Controller {
|
|
|
264
274
|
}
|
|
265
275
|
|
|
266
276
|
onMessageReceived(message) {
|
|
267
|
-
const { body, attachments } = message
|
|
277
|
+
const { id, body, attachments } = message
|
|
268
278
|
|
|
269
279
|
const div = document.createElement('div')
|
|
270
280
|
div.innerHTML = body
|
|
@@ -295,7 +305,10 @@ export default class extends Controller {
|
|
|
295
305
|
element.scrollIntoView({ behavior: 'smooth' })
|
|
296
306
|
this.setOfflineTimeout()
|
|
297
307
|
|
|
298
|
-
if (this.openValue)
|
|
308
|
+
if (this.openValue) {
|
|
309
|
+
this.messagesAPI.markAsSeen(id)
|
|
310
|
+
return
|
|
311
|
+
}
|
|
299
312
|
|
|
300
313
|
this.unreadCounterTarget.style.display = 'flex'
|
|
301
314
|
|
|
@@ -328,13 +341,22 @@ export default class extends Controller {
|
|
|
328
341
|
attachments: this.files,
|
|
329
342
|
}
|
|
330
343
|
|
|
331
|
-
|
|
344
|
+
if (this.inputTarget.value.trim().length === 0 && this.files.length === 0) {
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (this.inputTarget.value.trim().length > 0) {
|
|
349
|
+
formData.append('message[body]', this.inputTarget.value)
|
|
350
|
+
} else {
|
|
351
|
+
delete message.body
|
|
352
|
+
}
|
|
332
353
|
|
|
333
354
|
this.files.forEach(file => {
|
|
334
355
|
formData.append('message[attachments][]', file)
|
|
335
356
|
})
|
|
336
357
|
|
|
337
358
|
formData.append('session', Hellotext.session)
|
|
359
|
+
formData.append('locale', Locale.toString())
|
|
338
360
|
|
|
339
361
|
const element = this.messageTemplateTarget.cloneNode(true)
|
|
340
362
|
|
|
@@ -344,7 +366,12 @@ export default class extends Controller {
|
|
|
344
366
|
element.style.removeProperty('display')
|
|
345
367
|
|
|
346
368
|
element.setAttribute('data-hellotext--webchat-target', 'message')
|
|
347
|
-
|
|
369
|
+
|
|
370
|
+
if (this.inputTarget.value.trim().length > 0) {
|
|
371
|
+
element.querySelector('[data-body]').innerText = this.inputTarget.value
|
|
372
|
+
} else {
|
|
373
|
+
element.querySelector('[data-message-bubble]').remove()
|
|
374
|
+
}
|
|
348
375
|
|
|
349
376
|
const attachments = this.attachmentContainerTarget.querySelectorAll('img')
|
|
350
377
|
|
|
@@ -364,6 +391,10 @@ export default class extends Controller {
|
|
|
364
391
|
|
|
365
392
|
this.inputTarget.value = ''
|
|
366
393
|
this.files = []
|
|
394
|
+
|
|
395
|
+
this.attachmentInputTarget.value = ''
|
|
396
|
+
this.attachmentContainerTarget.innerHTML = ''
|
|
397
|
+
|
|
367
398
|
this.attachmentContainerTarget.style.display = 'none'
|
|
368
399
|
this.errorMessageContainerTarget.style.display = 'none'
|
|
369
400
|
|
|
@@ -401,9 +432,10 @@ export default class extends Controller {
|
|
|
401
432
|
onFileInputChange() {
|
|
402
433
|
this.errorMessageContainerTarget.style.display = 'none'
|
|
403
434
|
|
|
404
|
-
|
|
435
|
+
const newFiles = Array.from(this.attachmentInputTarget.files)
|
|
436
|
+
this.attachmentInputTarget.value = ''
|
|
405
437
|
|
|
406
|
-
const fileMaxSizeTooMuch =
|
|
438
|
+
const fileMaxSizeTooMuch = newFiles.find(file => {
|
|
407
439
|
const type = file.type.split('/')[0]
|
|
408
440
|
|
|
409
441
|
if (['image', 'video', 'audio'].includes(type)) {
|
|
@@ -421,11 +453,14 @@ export default class extends Controller {
|
|
|
421
453
|
'%{limit}',
|
|
422
454
|
this.byteToMegabyte(this.mediaValue[mediaType].max_size),
|
|
423
455
|
)
|
|
424
|
-
|
|
456
|
+
|
|
457
|
+
return (this.errorMessageContainerTarget.style.display = 'block')
|
|
425
458
|
}
|
|
426
459
|
|
|
460
|
+
this.files = [...this.files, ...newFiles]
|
|
427
461
|
this.errorMessageContainerTarget.innerText = ''
|
|
428
|
-
|
|
462
|
+
|
|
463
|
+
newFiles.forEach(file => this.createAttachmentElement(file))
|
|
429
464
|
this.inputTarget.focus()
|
|
430
465
|
}
|
|
431
466
|
|
|
@@ -448,12 +483,16 @@ export default class extends Controller {
|
|
|
448
483
|
this.attachmentContainerTarget.style.display = 'flex'
|
|
449
484
|
} else {
|
|
450
485
|
const main = element.querySelector('main')
|
|
486
|
+
|
|
451
487
|
main.style.height = '5rem'
|
|
452
488
|
main.style.borderRadius = '0.375rem'
|
|
453
489
|
main.style.backgroundColor = '#e5e7eb'
|
|
454
490
|
main.style.padding = '0.25rem'
|
|
455
491
|
|
|
456
492
|
element.querySelector('p[data-attachment-name]').innerText = file.name
|
|
493
|
+
|
|
494
|
+
this.attachmentContainerTarget.appendChild(element)
|
|
495
|
+
this.attachmentContainerTarget.style.display = 'flex'
|
|
457
496
|
}
|
|
458
497
|
}
|
|
459
498
|
|
|
@@ -461,6 +500,7 @@ export default class extends Controller {
|
|
|
461
500
|
const attachment = currentTarget.closest("[data-hellotext--webchat-target='attachment']")
|
|
462
501
|
|
|
463
502
|
this.files = this.files.filter(file => file.name !== attachment.dataset.name)
|
|
503
|
+
this.attachmentInputTarget.value = ''
|
|
464
504
|
|
|
465
505
|
attachment.remove()
|
|
466
506
|
this.inputTarget.focus()
|
|
@@ -513,4 +553,14 @@ export default class extends Controller {
|
|
|
513
553
|
get middlewares() {
|
|
514
554
|
return [offset(5), shift({ padding: 24 }), flip()]
|
|
515
555
|
}
|
|
556
|
+
|
|
557
|
+
get shouldOpenOnMount() {
|
|
558
|
+
return (
|
|
559
|
+
localStorage.getItem(`hellotext--webchat--${this.idValue}`) === 'opened' && !this.onMobile
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
get onMobile() {
|
|
564
|
+
return window.matchMedia(`(max-width: ${this.fullScreenThresholdValue}px)`).matches
|
|
565
|
+
}
|
|
516
566
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Locale
|
|
3
|
+
* @classdesc
|
|
4
|
+
* Handles locale detection and configuration for the Hellotext library.
|
|
5
|
+
* Provides automatic locale detection from HTML lang attribute, meta tags,
|
|
6
|
+
* and browser language with fallback to 'en'.
|
|
7
|
+
*/
|
|
8
|
+
class Locale {
|
|
9
|
+
static _identifier
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets the locale identifier explicitly.
|
|
13
|
+
* @param {string} value - The locale identifier (e.g., 'en', 'es')
|
|
14
|
+
*/
|
|
15
|
+
static set identifier(value) {
|
|
16
|
+
this._identifier = value
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Gets the effective locale identifier.
|
|
21
|
+
* Falls back to auto-detection if not explicitly set.
|
|
22
|
+
* @returns {string} The locale identifier
|
|
23
|
+
*/
|
|
24
|
+
static get identifier() {
|
|
25
|
+
if (this._identifier) return this._identifier
|
|
26
|
+
return this.#fromHtmlLangProperty || this.#fromMetaTag || this.#fromBrowserLanguage || 'en'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the locale identifier as a string.
|
|
31
|
+
* @returns {string} The locale identifier
|
|
32
|
+
*/
|
|
33
|
+
static toString() {
|
|
34
|
+
return this.identifier
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static get #fromHtmlLangProperty() {
|
|
38
|
+
return document?.documentElement?.lang
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static get #fromMetaTag() {
|
|
42
|
+
return document?.querySelector('meta[name="locale"]')?.content
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static get #fromBrowserLanguage() {
|
|
46
|
+
return navigator?.language?.split('-')[0] // Extract primary language
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { Locale }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Forms } from './configuration/forms'
|
|
2
|
+
import { Locale } from './configuration/locale'
|
|
2
3
|
import { Webchat } from './configuration/webchat'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -9,6 +10,7 @@ import { Webchat } from './configuration/webchat'
|
|
|
9
10
|
* @property {String} [session] - session id
|
|
10
11
|
* @property {Forms} [forms] - form configuration
|
|
11
12
|
* @property {Webchat} [webchat] - webchat configuration
|
|
13
|
+
* @property {Locale} [locale] - locale configuration
|
|
12
14
|
*/
|
|
13
15
|
class Configuration {
|
|
14
16
|
static apiRoot = 'https://api.hellotext.com/v1'
|
|
@@ -43,6 +45,14 @@ class Configuration {
|
|
|
43
45
|
return this
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
static set locale(locale) {
|
|
49
|
+
Locale.identifier = locale
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static get locale() {
|
|
53
|
+
return Locale.toString()
|
|
54
|
+
}
|
|
55
|
+
|
|
46
56
|
static endpoint(path) {
|
|
47
57
|
return `${this.apiRoot}/${path}`
|
|
48
58
|
}
|
package/src/core/index.js
CHANGED
package/src/locales/en.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
white_label: {
|
|
3
|
-
powered_by: '
|
|
3
|
+
powered_by: 'By',
|
|
4
4
|
},
|
|
5
5
|
errors: {
|
|
6
6
|
parameter_not_unique: 'This value is taken.',
|
|
7
|
-
blank: 'This field is required.'
|
|
7
|
+
blank: 'This field is required.',
|
|
8
8
|
},
|
|
9
9
|
forms: {
|
|
10
10
|
phone: 'Click the link sent via SMS to verify your submission.',
|
|
11
11
|
email: 'Click the link sent via email to verify your submission.',
|
|
12
12
|
phone_and_email: 'Click the links sent via SMS and email to verify your submission.',
|
|
13
|
-
none: 'Your submission has been received.'
|
|
14
|
-
}
|
|
13
|
+
none: 'Your submission has been received.',
|
|
14
|
+
},
|
|
15
15
|
}
|
package/src/locales/es.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
white_label: {
|
|
3
|
-
powered_by: '
|
|
3
|
+
powered_by: 'Por',
|
|
4
4
|
},
|
|
5
5
|
errors: {
|
|
6
6
|
parameter_not_unique: 'Este valor ya está en uso.',
|
|
7
|
-
blank: 'Este campo es obligatorio.'
|
|
7
|
+
blank: 'Este campo es obligatorio.',
|
|
8
8
|
},
|
|
9
9
|
forms: {
|
|
10
10
|
phone: 'Haga clic en el enlace enviado por SMS para verificar su envío.',
|
|
11
11
|
email: 'Haga clic en el enlace enviado por e-mail para verificar su envío.',
|
|
12
12
|
phone_and_email: 'Haga clic en los enlaces enviados por SMS y e-mail para verificar su envío.',
|
|
13
|
-
none: 'Su envío ha sido recibido.'
|
|
14
|
-
}
|
|
13
|
+
none: 'Su envío ha sido recibido.',
|
|
14
|
+
},
|
|
15
15
|
}
|
package/src/models/business.js
CHANGED
|
@@ -30,6 +30,18 @@ class Business {
|
|
|
30
30
|
return this.data.whitelist !== 'disabled'
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
setLocale(locale) {
|
|
34
|
+
if (!locales[locale]) {
|
|
35
|
+
return console.warn(`Locale ${locale} not found`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!this.data) {
|
|
39
|
+
this.data = {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.data.locale = locale
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
get locale() {
|
|
34
46
|
return locales[this.data.locale]
|
|
35
47
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import API from '../api/forms'
|
|
2
2
|
import Hellotext from '../hellotext'
|
|
3
3
|
|
|
4
|
-
import { Configuration } from '../core'
|
|
4
|
+
import { Configuration, Locale } from '../core'
|
|
5
5
|
import { Form } from './form'
|
|
6
6
|
|
|
7
7
|
import { NotInitializedError } from '../errors'
|
|
@@ -84,6 +84,7 @@ class FormCollection {
|
|
|
84
84
|
|
|
85
85
|
if (!Hellotext.business.data) {
|
|
86
86
|
Hellotext.business.setData(data.business)
|
|
87
|
+
Hellotext.business.setLocale(Locale.toString())
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
if (!Hellotext.business.enabledWhitelist) {
|
package/src/models/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Business } from './business'
|
|
2
|
-
export { Form } from './form'
|
|
3
|
-
export { Query } from './query'
|
|
4
2
|
export { Cookies } from './cookies'
|
|
3
|
+
export { Form } from './form'
|
|
5
4
|
export { FormCollection } from './form_collection'
|
|
6
|
-
export {
|
|
5
|
+
export { Query } from './query'
|
|
7
6
|
export { Session } from './session'
|
|
7
|
+
export { Webchat } from './webchat'
|