@hellotext/hellotext 1.8.3 → 1.8.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/__tests__/core/configuration/webchat_test.js +163 -0
- package/__tests__/hellotext_test.js +97 -101
- package/dist/hellotext.js +1 -1
- package/docs/webchat.md +101 -0
- package/jest.config.js +1 -0
- package/jest.setup.js +9 -0
- package/lib/api/index.js +6 -0
- package/lib/api/web_chat/messages.js +74 -0
- package/lib/api/web_chats.js +53 -0
- package/lib/api/webchat/messages.js +85 -0
- package/lib/api/webchats.js +53 -0
- package/lib/builders/logo_builder.js +2 -1
- package/lib/channels/application_channel.js +68 -0
- package/lib/channels/web_chat_channel.js +97 -0
- package/lib/channels/webchat_channel.js +112 -0
- package/lib/controllers/mixins/usePopover.js +61 -0
- package/lib/controllers/web_chat/pagination_controller.js +81 -0
- package/lib/controllers/webchat/emoji_picker_controller.js +134 -0
- package/lib/controllers/webchat_controller.js +446 -0
- package/lib/core/configuration/web_chat.js +168 -0
- package/lib/core/configuration/webchat.js +185 -0
- package/lib/core/configuration.js +6 -1
- package/lib/core/event.js +1 -1
- package/lib/hellotext.js +18 -9
- package/lib/index.js +4 -0
- package/lib/models/business.js +9 -1
- package/lib/models/index.js +7 -0
- package/lib/models/session.js +2 -0
- package/lib/models/web_chat.js +51 -0
- package/lib/models/webchat.js +51 -0
- package/package.json +8 -7
- package/src/api/index.js +5 -0
- package/src/api/webchat/messages.js +55 -0
- package/src/api/webchats.js +30 -0
- package/src/builders/logo_builder.js +8 -4
- package/src/channels/application_channel.js +45 -0
- package/src/channels/webchat_channel.js +77 -0
- package/src/controllers/mixins/usePopover.js +50 -0
- package/src/controllers/webchat/emoji_picker_controller.js +82 -0
- package/src/controllers/webchat_controller.js +448 -0
- package/src/core/configuration/webchat.js +176 -0
- package/src/core/configuration.js +5 -0
- package/src/core/event.js +10 -1
- package/src/hellotext.js +7 -2
- package/src/index.js +5 -0
- package/src/models/business.js +11 -1
- package/src/models/index.js +1 -0
- package/src/models/session.js +7 -5
- package/src/models/webchat.js +28 -0
- package/styles/index.css +4 -0
- package/webpack.config.js +1 -1
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'} Placement
|
|
3
|
+
* @description Valid placements for the webchat.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @enum {Placement}
|
|
8
|
+
*/
|
|
9
|
+
const placements = {
|
|
10
|
+
TOP_LEFT: 'top-left',
|
|
11
|
+
TOP_RIGHT: 'top-right',
|
|
12
|
+
BOTTOM_LEFT: 'bottom-left',
|
|
13
|
+
BOTTOM_RIGHT: 'bottom-right'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {'modal' | 'popover'} Behaviour
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @enum {Behaviour}
|
|
23
|
+
*/
|
|
24
|
+
const behaviors = {
|
|
25
|
+
MODAL: 'modal',
|
|
26
|
+
POPOVER: 'popover'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {Object} Style
|
|
31
|
+
* @property {string} primaryColor - The primary webchat color (e.g., a hex code or color name).
|
|
32
|
+
* @property {string} secondaryColor - The secondary webchat color or style (e.g., a hex code or color name).
|
|
33
|
+
* @property {string} typography - The typography style (e.g., font family).
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @class Webchat
|
|
39
|
+
* @classdesc
|
|
40
|
+
* Configuration for webchat
|
|
41
|
+
* @property {String} id - the id of the webchat.
|
|
42
|
+
* @property {String} container - the container to append the webchat to, defaults to 'body'
|
|
43
|
+
* @property {Placement} placement - the placement of the webchat within the container, defaults to "bottom-right".
|
|
44
|
+
* @property {String} classes - additional classes to apply to the webchat popup.
|
|
45
|
+
* @property {String} triggerClasses - additional classes to apply to the webchat popup trigger.
|
|
46
|
+
* @property {Behaviour} behaviour - the behaviour of the webchat, defaults to 'popover'.
|
|
47
|
+
* @property {Style} style - the style of the webchat.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
class Webchat {
|
|
51
|
+
static _id
|
|
52
|
+
static _container = 'body'
|
|
53
|
+
static _placement = 'bottom-right'
|
|
54
|
+
static _classes = []
|
|
55
|
+
static _triggerClasses = []
|
|
56
|
+
static _style = {}
|
|
57
|
+
static _behaviour = behaviors.POPOVER
|
|
58
|
+
|
|
59
|
+
static set container(value) {
|
|
60
|
+
this._container = value
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static get container() {
|
|
64
|
+
return this._container
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static set placement(value) {
|
|
68
|
+
if(!Object.values(placements).includes(value)) {
|
|
69
|
+
throw new Error(`Invalid placement value: ${value}`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this._placement = value
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static get placement() {
|
|
76
|
+
return this._placement
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static set classes(value) {
|
|
80
|
+
if(!Array.isArray(value) && typeof value !== 'string') {
|
|
81
|
+
throw new Error('classes must be an array or a string')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this._classes = value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static get classes() {
|
|
88
|
+
if(typeof this._classes === 'string') {
|
|
89
|
+
return this._classes.split(',').map(c => c.trim())
|
|
90
|
+
} else {
|
|
91
|
+
return this._classes;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static set triggerClasses(value) {
|
|
96
|
+
if(!Array.isArray(value) && typeof value !== 'string') {
|
|
97
|
+
throw new Error('triggerClasses must be an array or a string')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this._triggerClasses = value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static get triggerClasses() {
|
|
104
|
+
if(typeof this._triggerClasses === 'string') {
|
|
105
|
+
return this._triggerClasses.split(',').map(c => c.trim())
|
|
106
|
+
} else {
|
|
107
|
+
return this._triggerClasses;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static set id(value) {
|
|
112
|
+
this._id = value
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static get id() {
|
|
116
|
+
return this._id
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static get isSet() {
|
|
120
|
+
return !!this._id
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static get style() {
|
|
124
|
+
return this._style
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static set style(value) {
|
|
128
|
+
if(typeof value !== 'object') {
|
|
129
|
+
throw new Error('Style must be an object')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Object.entries(value).forEach(([key, value]) => {
|
|
133
|
+
if(!['primaryColor', 'secondaryColor', 'typography'].includes(key)) {
|
|
134
|
+
throw new Error(`Invalid style property: ${key}`)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if(key === 'typography') {
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if(!this.isHexOrRgba(value)) {
|
|
142
|
+
throw new Error(`Invalid color value: ${value} for ${key}. Colors must be hex or rgb/a.`)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
this._style = value
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static get behaviour() {
|
|
150
|
+
return this._behaviour
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static set behaviour(value) {
|
|
154
|
+
if(!Object.values(behaviors).includes(value)) {
|
|
155
|
+
throw new Error(`Invalid behaviour value: ${value}`)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this._behaviour = value
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static assign(props) {
|
|
162
|
+
if(props) {
|
|
163
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
164
|
+
this[key] = value
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return this
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static isHexOrRgba(value) {
|
|
172
|
+
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value) || /^rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3},?\s*(0|1|0?\.\d+)?\s*\)$/.test(value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export { Webchat, behaviors }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Forms } from './configuration/forms'
|
|
2
|
+
import { Webchat } from './configuration/webchat'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @class Configuration
|
|
@@ -7,6 +8,7 @@ import { Forms } from './configuration/forms'
|
|
|
7
8
|
* @property {Boolean} [autoGenerateSession=true] - whether to auto generate session or not
|
|
8
9
|
* @property {String} [session] - session id
|
|
9
10
|
* @property {Forms} [forms] - form configuration
|
|
11
|
+
* @property {Webchat} [webchat] - webchat configuration
|
|
10
12
|
*/
|
|
11
13
|
class Configuration {
|
|
12
14
|
static apiRoot = 'https://api.hellotext.com/v1'
|
|
@@ -15,6 +17,7 @@ class Configuration {
|
|
|
15
17
|
static session = null
|
|
16
18
|
|
|
17
19
|
static forms = Forms
|
|
20
|
+
static webchat = Webchat
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
*
|
|
@@ -29,6 +32,8 @@ class Configuration {
|
|
|
29
32
|
Object.entries(props).forEach(([key, value]) => {
|
|
30
33
|
if (key === 'forms') {
|
|
31
34
|
this.forms = Forms.assign(value)
|
|
35
|
+
} else if(key === 'webChat') {
|
|
36
|
+
this.webchat = Webchat.assign(value)
|
|
32
37
|
} else {
|
|
33
38
|
this[key] = value
|
|
34
39
|
}
|
package/src/core/event.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { InvalidEvent } from '../errors'
|
|
2
2
|
|
|
3
3
|
export default class Event {
|
|
4
|
-
static events = [
|
|
4
|
+
static events = [
|
|
5
|
+
'session-set',
|
|
6
|
+
'forms:collected',
|
|
7
|
+
'form:completed',
|
|
8
|
+
'webchat:mounted',
|
|
9
|
+
'webchat:opened',
|
|
10
|
+
'webchat:closed',
|
|
11
|
+
'webchat:message:sent',
|
|
12
|
+
'webchat:message:received',
|
|
13
|
+
]
|
|
5
14
|
|
|
6
15
|
static valid(name) {
|
|
7
16
|
return Event.exists(name)
|
package/src/hellotext.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Event, Configuration } from './core'
|
|
2
2
|
|
|
3
3
|
import API, { Response } from './api'
|
|
4
|
-
import { Business, Query, FormCollection, Session } from './models'
|
|
4
|
+
import { Business, Query, FormCollection, Session, Webchat } from './models'
|
|
5
5
|
|
|
6
6
|
import { NotInitializedError } from './errors'
|
|
7
7
|
|
|
@@ -13,13 +13,14 @@ class Hellotext {
|
|
|
13
13
|
static eventEmitter = new Event()
|
|
14
14
|
static forms
|
|
15
15
|
static business
|
|
16
|
+
static webchat
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* initialize the module.
|
|
19
20
|
* @param business public business id
|
|
20
21
|
* @param { Configuration } config
|
|
21
22
|
*/
|
|
22
|
-
static initialize(business, config) {
|
|
23
|
+
static async initialize(business, config) {
|
|
23
24
|
Configuration.assign(config)
|
|
24
25
|
Session.initialize()
|
|
25
26
|
|
|
@@ -27,6 +28,10 @@ class Hellotext {
|
|
|
27
28
|
|
|
28
29
|
this.business = new Business(business)
|
|
29
30
|
this.forms = new FormCollection()
|
|
31
|
+
|
|
32
|
+
if (Configuration.webchat.id) {
|
|
33
|
+
this.webchat = await Webchat.load(Configuration.webchat.id)
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
/**
|
package/src/index.js
CHANGED
|
@@ -2,9 +2,14 @@ import { Application } from '@hotwired/stimulus'
|
|
|
2
2
|
import Hellotext from './hellotext'
|
|
3
3
|
|
|
4
4
|
import FormController from './controllers/form_controller'
|
|
5
|
+
import WebchatController from './controllers/webchat_controller'
|
|
6
|
+
import WebChatEmojiController from './controllers/webchat/emoji_picker_controller'
|
|
5
7
|
|
|
6
8
|
const application = Application.start()
|
|
9
|
+
|
|
7
10
|
application.register('hellotext--form', FormController)
|
|
11
|
+
application.register('hellotext--webchat', WebchatController)
|
|
12
|
+
application.register('hellotext--webchat--emoji', WebChatEmojiController)
|
|
8
13
|
|
|
9
14
|
import '../styles/index.css'
|
|
10
15
|
|
package/src/models/business.js
CHANGED
|
@@ -34,7 +34,17 @@ class Business {
|
|
|
34
34
|
fetchPublicData() {
|
|
35
35
|
API.get(this.id)
|
|
36
36
|
.then(response => response.json())
|
|
37
|
-
.then(data =>
|
|
37
|
+
.then(data => {
|
|
38
|
+
this.data = data
|
|
39
|
+
|
|
40
|
+
if(typeof document !== 'undefined') {
|
|
41
|
+
const linkTag = document.createElement('link')
|
|
42
|
+
linkTag.rel = 'stylesheet'
|
|
43
|
+
linkTag.href = data.style_url
|
|
44
|
+
|
|
45
|
+
document.head.append(linkTag)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
50
|
|
package/src/models/index.js
CHANGED
package/src/models/session.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {Configuration} from '../core';
|
|
2
|
+
import {Cookies, Query} from './index'
|
|
3
3
|
|
|
4
4
|
class Session {
|
|
5
5
|
static #session
|
|
@@ -17,14 +17,16 @@ class Session {
|
|
|
17
17
|
static initialize() {
|
|
18
18
|
this.#query = new Query()
|
|
19
19
|
|
|
20
|
-
if(Configuration.session) {
|
|
20
|
+
if (Configuration.session) {
|
|
21
21
|
this.session = Configuration.session
|
|
22
22
|
} else if (this.#query.session) {
|
|
23
|
-
this.session =
|
|
23
|
+
this.session = this.#query.session
|
|
24
|
+
} else if (Cookies.get('hello_session')) {
|
|
25
|
+
this.session = Cookies.get('hello_session')
|
|
24
26
|
} else if (Configuration.autoGenerateSession) {
|
|
25
27
|
this.session = crypto.randomUUID()
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
export {
|
|
32
|
+
export {Session}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Hellotext from '../hellotext';
|
|
2
|
+
import { Configuration } from '../core'
|
|
3
|
+
|
|
4
|
+
import API from '../api';
|
|
5
|
+
|
|
6
|
+
class Webchat {
|
|
7
|
+
static async load(id) {
|
|
8
|
+
return new Webchat({
|
|
9
|
+
id,
|
|
10
|
+
html: await API.webchats.get(id),
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(data) {
|
|
15
|
+
this.data = data
|
|
16
|
+
this.render()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
render() {
|
|
20
|
+
this.containerToAppendTo.appendChild(this.data.html)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get containerToAppendTo() {
|
|
24
|
+
return document.querySelector(Configuration.webchat.container)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { Webchat }
|
package/styles/index.css
CHANGED