@hellotext/hellotext 2.3.8 → 2.4.0

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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/hellotext.js +1 -1
  3. package/dist/webchat-emoji-en.js +1 -0
  4. package/dist/webchat-emoji-es.js +1 -0
  5. package/dist/webchat-emoji.js +1 -0
  6. package/index.d.ts +74 -15
  7. package/lib/api/webchats.cjs +20 -0
  8. package/lib/api/webchats.js +20 -0
  9. package/lib/controllers/mixins/usePopover.cjs +7 -2
  10. package/lib/controllers/mixins/usePopover.js +7 -2
  11. package/lib/controllers/webchat/emoji_picker_controller.cjs +49 -10
  12. package/lib/controllers/webchat/emoji_picker_controller.js +66 -8
  13. package/lib/controllers/webchat/useBehaviour.cjs +74 -0
  14. package/lib/controllers/webchat/useBehaviour.js +67 -0
  15. package/lib/controllers/webchat/useOpeningSequence.cjs +103 -0
  16. package/lib/controllers/webchat/useOpeningSequence.js +96 -0
  17. package/lib/controllers/webchat/useTeaser.cjs +163 -0
  18. package/lib/controllers/webchat/useTeaser.js +156 -0
  19. package/lib/controllers/webchat_controller.cjs +165 -22
  20. package/lib/controllers/webchat_controller.js +173 -24
  21. package/lib/core/configuration/webchat.cjs +117 -42
  22. package/lib/core/configuration/webchat.js +121 -43
  23. package/lib/hellotext.cjs +33 -3
  24. package/lib/hellotext.js +37 -6
  25. package/lib/models/business.cjs +71 -0
  26. package/lib/models/business.js +82 -0
  27. package/lib/models/webchat.cjs +25 -0
  28. package/lib/models/webchat.js +25 -0
  29. package/package.json +1 -1
  30. package/src/api/webchats.js +17 -0
  31. package/src/controllers/mixins/usePopover.js +4 -2
  32. package/src/controllers/webchat/emoji_picker_controller.js +51 -9
  33. package/src/controllers/webchat/useBehaviour.js +81 -0
  34. package/src/controllers/webchat/useOpeningSequence.js +127 -0
  35. package/src/controllers/webchat/useTeaser.js +192 -0
  36. package/src/controllers/webchat_controller.js +187 -23
  37. package/src/core/configuration/webchat.js +127 -43
  38. package/src/hellotext.js +38 -3
  39. package/src/models/business.js +76 -0
  40. package/src/models/webchat.js +28 -0
@@ -33,13 +33,13 @@ var strategies = {
33
33
  };
34
34
 
35
35
  /**
36
- * @typedef {'modal' | 'popover'} Behaviour
36
+ * @typedef {'modal' | 'popover'} Mode
37
37
  */
38
38
 
39
39
  /**
40
- * @enum {Behaviour}
40
+ * @enum {Mode}
41
41
  */
42
- var behaviors = {
42
+ var modes = {
43
43
  MODAL: 'modal',
44
44
  POPOVER: 'popover'
45
45
  };
@@ -51,6 +51,20 @@ var behaviors = {
51
51
  * @property {string} typography - The typography style (e.g., font family).
52
52
  */
53
53
 
54
+ /**
55
+ * @typedef {Object} Appearance
56
+ * @property {Object} [header] - Header appearance overrides.
57
+ * @property {string} [header.name] - Business name shown in the webchat header.
58
+ * @property {Object} [launcher] - Launcher appearance overrides.
59
+ * @property {string} [launcher.iconUrl] - Image URL used for the launcher icon.
60
+ */
61
+
62
+ /**
63
+ * @typedef {Object} WhatsApp
64
+ * @property {string} [number] - WhatsApp number used by the handoff configuration.
65
+ * @property {boolean} [restrictToChannel] - Whether handoff should be restricted to the configured channel.
66
+ */
67
+
54
68
  /**
55
69
  * @class Webchat
56
70
  * @classdesc
@@ -58,10 +72,11 @@ var behaviors = {
58
72
  * @property {String} id - the id of the webchat.
59
73
  * @property {String} container - the container to append the webchat to, defaults to 'body'
60
74
  * @property {Placement} placement - the placement of the webchat within the container, defaults to "bottom-right".
61
- * @property {String} classes - additional classes to apply to the webchat popup.
62
- * @property {String} triggerClasses - additional classes to apply to the webchat popup trigger.
63
- * @property {Behaviour} behaviour - the behaviour of the webchat, defaults to 'popover'.
75
+ * @property {Mode} mode - how the webchat behaves while open, defaults to 'popover'.
76
+ * @property {Object} behaviour - runtime opening behaviour for the webchat.
64
77
  * @property {Style} style - the style of the webchat.
78
+ * @property {Appearance} appearance - appearance overrides.
79
+ * @property {WhatsApp} whatsapp - WhatsApp handoff overrides.
65
80
  * @property {Strategy} strategy - the strategy used to position the webchat. Defaults to 'absolute'
66
81
  */
67
82
  var Webchat = /*#__PURE__*/function () {
@@ -87,36 +102,6 @@ var Webchat = /*#__PURE__*/function () {
87
102
  }
88
103
  this._placement = value;
89
104
  }
90
- }, {
91
- key: "classes",
92
- get: function get() {
93
- if (typeof this._classes === 'string') {
94
- return this._classes.split(',').map(c => c.trim());
95
- } else {
96
- return this._classes;
97
- }
98
- },
99
- set: function set(value) {
100
- if (!Array.isArray(value) && typeof value !== 'string') {
101
- throw new Error('classes must be an array or a string');
102
- }
103
- this._classes = value;
104
- }
105
- }, {
106
- key: "triggerClasses",
107
- get: function get() {
108
- if (typeof this._triggerClasses === 'string') {
109
- return this._triggerClasses.split(',').map(c => c.trim());
110
- } else {
111
- return this._triggerClasses;
112
- }
113
- },
114
- set: function set(value) {
115
- if (!Array.isArray(value) && typeof value !== 'string') {
116
- throw new Error('triggerClasses must be an array or a string');
117
- }
118
- this._triggerClasses = value;
119
- }
120
105
  }, {
121
106
  key: "id",
122
107
  get: function get() {
@@ -153,17 +138,103 @@ var Webchat = /*#__PURE__*/function () {
153
138
  });
154
139
  this._style = value;
155
140
  }
141
+ }, {
142
+ key: "appearance",
143
+ get: function get() {
144
+ return this._appearance;
145
+ },
146
+ set: function set(value) {
147
+ if (!this.isPlainObject(value)) {
148
+ throw new Error('Appearance must be an object');
149
+ }
150
+ Object.entries(value).forEach(_ref2 => {
151
+ var [key, nestedValue] = _ref2;
152
+ if (!['header', 'launcher'].includes(key)) {
153
+ throw new Error("Invalid appearance property: ".concat(key));
154
+ }
155
+ if (!this.isPlainObject(nestedValue)) {
156
+ throw new Error("Appearance ".concat(key, " must be an object"));
157
+ }
158
+ Object.entries(nestedValue).forEach(_ref3 => {
159
+ var [nestedKey, propertyValue] = _ref3;
160
+ if (key === 'header' && nestedKey !== 'name') {
161
+ throw new Error("Invalid appearance header property: ".concat(nestedKey));
162
+ }
163
+ if (key === 'launcher' && nestedKey !== 'iconUrl') {
164
+ throw new Error("Invalid appearance launcher property: ".concat(nestedKey));
165
+ }
166
+ if (propertyValue == null) {
167
+ return;
168
+ }
169
+ if (typeof propertyValue !== 'string') {
170
+ throw new Error("Invalid appearance ".concat(key, ".").concat(nestedKey, " value: ").concat(propertyValue));
171
+ }
172
+ });
173
+ });
174
+ this._appearance = value;
175
+ }
176
+ }, {
177
+ key: "whatsapp",
178
+ get: function get() {
179
+ return this._whatsapp;
180
+ },
181
+ set: function set(value) {
182
+ if (!this.isPlainObject(value)) {
183
+ throw new Error('WhatsApp must be an object');
184
+ }
185
+ Object.entries(value).forEach(_ref4 => {
186
+ var [key, nestedValue] = _ref4;
187
+ if (!['number', 'restrictToChannel'].includes(key)) {
188
+ throw new Error("Invalid WhatsApp property: ".concat(key));
189
+ }
190
+ if (nestedValue == null) {
191
+ return;
192
+ }
193
+ if (key === 'number' && typeof nestedValue !== 'string') {
194
+ throw new Error("Invalid WhatsApp number value: ".concat(nestedValue));
195
+ }
196
+ if (key === 'restrictToChannel' && typeof nestedValue !== 'boolean') {
197
+ throw new Error("Invalid WhatsApp restrictToChannel value: ".concat(nestedValue));
198
+ }
199
+ });
200
+ this._whatsapp = value;
201
+ }
202
+ }, {
203
+ key: "mode",
204
+ get: function get() {
205
+ return this._mode;
206
+ },
207
+ set: function set(value) {
208
+ if (!Object.values(modes).includes(value)) {
209
+ throw new Error("Invalid mode value: ".concat(value));
210
+ }
211
+ this._mode = value;
212
+ }
156
213
  }, {
157
214
  key: "behaviour",
158
215
  get: function get() {
159
216
  return this._behaviour;
160
217
  },
161
218
  set: function set(value) {
162
- if (!Object.values(behaviors).includes(value)) {
219
+ if (value == null) {
220
+ this._behaviour = value;
221
+ return;
222
+ }
223
+ if (typeof value !== 'object' || Array.isArray(value)) {
163
224
  throw new Error("Invalid behaviour value: ".concat(value));
164
225
  }
165
226
  this._behaviour = value;
166
227
  }
228
+ }, {
229
+ key: "hasBehaviourOverride",
230
+ get: function get() {
231
+ return this._hasBehaviourOverride;
232
+ }
233
+ }, {
234
+ key: "behaviourOverride",
235
+ set: function set(value) {
236
+ this._hasBehaviourOverride = !!value;
237
+ }
167
238
  }, {
168
239
  key: "strategy",
169
240
  get: function get() {
@@ -182,8 +253,8 @@ var Webchat = /*#__PURE__*/function () {
182
253
  key: "assign",
183
254
  value: function assign(props) {
184
255
  if (props) {
185
- Object.entries(props).forEach(_ref2 => {
186
- var [key, value] = _ref2;
256
+ Object.entries(props).forEach(_ref5 => {
257
+ var [key, value] = _ref5;
187
258
  this[key] = value;
188
259
  });
189
260
  }
@@ -194,15 +265,22 @@ var Webchat = /*#__PURE__*/function () {
194
265
  value: function isHexOrRgba(value) {
195
266
  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);
196
267
  }
268
+ }, {
269
+ key: "isPlainObject",
270
+ value: function isPlainObject(value) {
271
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
272
+ }
197
273
  }]);
198
274
  return Webchat;
199
275
  }();
200
276
  Webchat._id = void 0;
201
277
  Webchat._container = 'body';
202
278
  Webchat._placement = 'bottom-right';
203
- Webchat._classes = [];
204
- Webchat._triggerClasses = [];
205
279
  Webchat._style = {};
206
- Webchat._behaviour = behaviors.POPOVER;
280
+ Webchat._appearance = {};
281
+ Webchat._whatsapp = {};
282
+ Webchat._mode = modes.POPOVER;
283
+ Webchat._behaviour = null;
284
+ Webchat._hasBehaviourOverride = false;
207
285
  Webchat._strategy = null;
208
- export { behaviors, Webchat };
286
+ export { modes, Webchat };
package/lib/hellotext.cjs CHANGED
@@ -27,20 +27,50 @@ let Hellotext = /*#__PURE__*/function () {
27
27
  * @param business public business id
28
28
  * @param { Configuration } config
29
29
  */
30
- async function initialize(business, config) {
30
+ async function initialize(business, config = {}) {
31
31
  this.business = new _models.Business(business);
32
32
  _core.Configuration.assign(config);
33
33
  _models.Session.initialize();
34
34
  this.page = new _models.Page();
35
35
  this.forms = new _models.FormCollection();
36
36
  this.query = new _models.Query();
37
- if (_core.Configuration.webchat.id) {
38
- this.webchat = await _models.Webchat.load(_core.Configuration.webchat.id);
37
+ const businessData = await this.business.hydrate();
38
+ const webchatConfig = config.webchat === false ? false : this.mergeWebchatConfig(businessData && businessData.webchat || {}, config.webchat || {});
39
+ const hasExplicitBehaviourOverride = config.webchat && config.webchat !== false && Object.prototype.hasOwnProperty.call(config.webchat, 'behaviour');
40
+ _core.Configuration.webchat.behaviourOverride = hasExplicitBehaviourOverride;
41
+ if (webchatConfig && webchatConfig.id) {
42
+ _core.Configuration.webchat.assign(webchatConfig);
43
+ this.webchat = await _models.Webchat.load(webchatConfig.id);
39
44
  }
40
45
  if (typeof MutationObserver !== 'undefined') {
41
46
  this.forms.collectExistingFormsOnPage();
42
47
  }
43
48
  }
49
+ }, {
50
+ key: "mergeWebchatConfig",
51
+ value: function mergeWebchatConfig(dashboardConfig, localConfig) {
52
+ return this.deepMergePlainObjects(dashboardConfig, localConfig);
53
+ }
54
+ }, {
55
+ key: "deepMergePlainObjects",
56
+ value: function deepMergePlainObjects(base, override) {
57
+ const result = {
58
+ ...base
59
+ };
60
+ Object.entries(override).forEach(([key, value]) => {
61
+ if (this.isPlainObject(value) && this.isPlainObject(result[key])) {
62
+ result[key] = this.deepMergePlainObjects(result[key], value);
63
+ } else {
64
+ result[key] = value;
65
+ }
66
+ });
67
+ return result;
68
+ }
69
+ }, {
70
+ key: "isPlainObject",
71
+ value: function isPlainObject(value) {
72
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
73
+ }
44
74
 
45
75
  /**
46
76
  * Tracks an action that has happened on the page
package/lib/hellotext.js CHANGED
@@ -25,25 +25,56 @@ var Hellotext = /*#__PURE__*/function () {
25
25
  * @param { Configuration } config
26
26
  */
27
27
  function () {
28
- var _initialize = _asyncToGenerator(function* (business, config) {
28
+ var _initialize = _asyncToGenerator(function* (business) {
29
+ var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
29
30
  this.business = new Business(business);
30
31
  Configuration.assign(config);
31
32
  Session.initialize();
32
33
  this.page = new Page();
33
34
  this.forms = new FormCollection();
34
35
  this.query = new Query();
35
- if (Configuration.webchat.id) {
36
- this.webchat = yield Webchat.load(Configuration.webchat.id);
36
+ var businessData = yield this.business.hydrate();
37
+ var webchatConfig = config.webchat === false ? false : this.mergeWebchatConfig(businessData && businessData.webchat || {}, config.webchat || {});
38
+ var hasExplicitBehaviourOverride = config.webchat && config.webchat !== false && Object.prototype.hasOwnProperty.call(config.webchat, 'behaviour');
39
+ Configuration.webchat.behaviourOverride = hasExplicitBehaviourOverride;
40
+ if (webchatConfig && webchatConfig.id) {
41
+ Configuration.webchat.assign(webchatConfig);
42
+ this.webchat = yield Webchat.load(webchatConfig.id);
37
43
  }
38
44
  if (typeof MutationObserver !== 'undefined') {
39
45
  this.forms.collectExistingFormsOnPage();
40
46
  }
41
47
  });
42
- function initialize(_x, _x2) {
48
+ function initialize(_x) {
43
49
  return _initialize.apply(this, arguments);
44
50
  }
45
51
  return initialize;
46
52
  }()
53
+ }, {
54
+ key: "mergeWebchatConfig",
55
+ value: function mergeWebchatConfig(dashboardConfig, localConfig) {
56
+ return this.deepMergePlainObjects(dashboardConfig, localConfig);
57
+ }
58
+ }, {
59
+ key: "deepMergePlainObjects",
60
+ value: function deepMergePlainObjects(base, override) {
61
+ var result = _objectSpread({}, base);
62
+ Object.entries(override).forEach(_ref => {
63
+ var [key, value] = _ref;
64
+ if (this.isPlainObject(value) && this.isPlainObject(result[key])) {
65
+ result[key] = this.deepMergePlainObjects(result[key], value);
66
+ } else {
67
+ result[key] = value;
68
+ }
69
+ });
70
+ return result;
71
+ }
72
+ }, {
73
+ key: "isPlainObject",
74
+ value: function isPlainObject(value) {
75
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
76
+ }
77
+
47
78
  /**
48
79
  * Tracks an action that has happened on the page
49
80
  *
@@ -73,7 +104,7 @@ var Hellotext = /*#__PURE__*/function () {
73
104
  body
74
105
  });
75
106
  });
76
- function track(_x3) {
107
+ function track(_x2) {
77
108
  return _track.apply(this, arguments);
78
109
  }
79
110
  return track;
@@ -121,7 +152,7 @@ var Hellotext = /*#__PURE__*/function () {
121
152
  }
122
153
  return response;
123
154
  });
124
- function identify(_x4) {
155
+ function identify(_x3) {
125
156
  return _identify.apply(this, arguments);
126
157
  }
127
158
  return identify;
@@ -5,19 +5,85 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Business = void 0;
7
7
  var _locales = _interopRequireDefault(require("../locales"));
8
+ var _businesses = _interopRequireDefault(require("../api/businesses"));
8
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
10
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
11
  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); } }
11
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; }
12
13
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
13
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
+ /**
16
+ * @typedef {Object} BusinessCountry
17
+ * @property {String} [code] - ISO country code configured for the business.
18
+ * @property {String} [prefix] - Phone country prefix configured for the business.
19
+ */
20
+ /**
21
+ * @typedef {Object} BusinessWebchat
22
+ * @property {String} [id] - Dashboard webchat id configured for the business.
23
+ * @property {Object} [appearance] - Dashboard appearance defaults for the webchat.
24
+ * @property {Object} [whatsapp] - Dashboard WhatsApp handoff defaults for the webchat.
25
+ */
26
+ /**
27
+ * Public business metadata returned by `public/businesses/:id`.
28
+ *
29
+ * @typedef {Object} BusinessData
30
+ * @property {String} [id] - Public business id.
31
+ * @property {BusinessCountry|String} [country] - Business country metadata.
32
+ * @property {Object} [features] - Feature flags enabled for the business.
33
+ * @property {String} [locale] - Default dashboard locale for the business.
34
+ * @property {String} [style_url] - Stylesheet URL to inject for dashboard-managed surfaces.
35
+ * @property {BusinessWebchat|null} [webchat] - Dashboard webchat defaults.
36
+ * @property {String|Array<String>} [whitelist] - Domain whitelist configuration.
37
+ * @property {String} [subscription] - Current business subscription tier.
38
+ */
39
+ /**
40
+ * Public business context used by the SDK for tracking, forms, and webchat defaults.
41
+ */
14
42
  let Business = /*#__PURE__*/function () {
43
+ /**
44
+ * @param {String} id - Public business id.
45
+ */
15
46
  function Business(id) {
16
47
  _classCallCheck(this, Business);
17
48
  this.id = id;
18
49
  this.data = null;
19
50
  }
51
+
52
+ /**
53
+ * Hydrates business metadata from the public business endpoint.
54
+ *
55
+ * Fetch failures return `null` so tracking initialization can continue even
56
+ * when dashboard-driven webchat defaults are unavailable.
57
+ *
58
+ * @returns {Promise<BusinessData|null>}
59
+ */
20
60
  _createClass(Business, [{
61
+ key: "hydrate",
62
+ value: async function hydrate() {
63
+ try {
64
+ const response = await _businesses.default.get(this.id);
65
+ if (response.ok === false) {
66
+ return null;
67
+ }
68
+ const business = await response.json();
69
+ if (!business) {
70
+ return null;
71
+ }
72
+ this.setData(business);
73
+ if (business.locale) {
74
+ this.setLocale(business.locale);
75
+ }
76
+ return business;
77
+ } catch (_error) {
78
+ return null;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {BusinessData} data
84
+ * @returns {void}
85
+ */
86
+ }, {
21
87
  key: "setData",
22
88
  value: function setData(data) {
23
89
  this.data = data;
@@ -43,6 +109,11 @@ let Business = /*#__PURE__*/function () {
43
109
  get: function () {
44
110
  return this.data.whitelist !== 'disabled';
45
111
  }
112
+
113
+ /**
114
+ * @param {String} locale
115
+ * @returns {void}
116
+ */
46
117
  }, {
47
118
  key: "setLocale",
48
119
  value: function setLocale(locale) {
@@ -1,16 +1,93 @@
1
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
2
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
1
3
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2
4
  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); } }
3
5
  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
6
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
5
7
  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
8
  import locales from '../locales';
9
+ import BusinessesAPI from '../api/businesses';
10
+
11
+ /**
12
+ * @typedef {Object} BusinessCountry
13
+ * @property {String} [code] - ISO country code configured for the business.
14
+ * @property {String} [prefix] - Phone country prefix configured for the business.
15
+ */
16
+
17
+ /**
18
+ * @typedef {Object} BusinessWebchat
19
+ * @property {String} [id] - Dashboard webchat id configured for the business.
20
+ * @property {Object} [appearance] - Dashboard appearance defaults for the webchat.
21
+ * @property {Object} [whatsapp] - Dashboard WhatsApp handoff defaults for the webchat.
22
+ */
23
+
24
+ /**
25
+ * Public business metadata returned by `public/businesses/:id`.
26
+ *
27
+ * @typedef {Object} BusinessData
28
+ * @property {String} [id] - Public business id.
29
+ * @property {BusinessCountry|String} [country] - Business country metadata.
30
+ * @property {Object} [features] - Feature flags enabled for the business.
31
+ * @property {String} [locale] - Default dashboard locale for the business.
32
+ * @property {String} [style_url] - Stylesheet URL to inject for dashboard-managed surfaces.
33
+ * @property {BusinessWebchat|null} [webchat] - Dashboard webchat defaults.
34
+ * @property {String|Array<String>} [whitelist] - Domain whitelist configuration.
35
+ * @property {String} [subscription] - Current business subscription tier.
36
+ */
37
+
38
+ /**
39
+ * Public business context used by the SDK for tracking, forms, and webchat defaults.
40
+ */
7
41
  var Business = /*#__PURE__*/function () {
42
+ /**
43
+ * @param {String} id - Public business id.
44
+ */
8
45
  function Business(id) {
9
46
  _classCallCheck(this, Business);
10
47
  this.id = id;
11
48
  this.data = null;
12
49
  }
50
+
51
+ /**
52
+ * Hydrates business metadata from the public business endpoint.
53
+ *
54
+ * Fetch failures return `null` so tracking initialization can continue even
55
+ * when dashboard-driven webchat defaults are unavailable.
56
+ *
57
+ * @returns {Promise<BusinessData|null>}
58
+ */
13
59
  _createClass(Business, [{
60
+ key: "hydrate",
61
+ value: function () {
62
+ var _hydrate = _asyncToGenerator(function* () {
63
+ try {
64
+ var response = yield BusinessesAPI.get(this.id);
65
+ if (response.ok === false) {
66
+ return null;
67
+ }
68
+ var business = yield response.json();
69
+ if (!business) {
70
+ return null;
71
+ }
72
+ this.setData(business);
73
+ if (business.locale) {
74
+ this.setLocale(business.locale);
75
+ }
76
+ return business;
77
+ } catch (_error) {
78
+ return null;
79
+ }
80
+ });
81
+ function hydrate() {
82
+ return _hydrate.apply(this, arguments);
83
+ }
84
+ return hydrate;
85
+ }()
86
+ /**
87
+ * @param {BusinessData} data
88
+ * @returns {void}
89
+ */
90
+ }, {
14
91
  key: "setData",
15
92
  value: function setData(data) {
16
93
  this.data = data;
@@ -36,6 +113,11 @@ var Business = /*#__PURE__*/function () {
36
113
  get: function get() {
37
114
  return this.data.whitelist !== 'disabled';
38
115
  }
116
+
117
+ /**
118
+ * @param {String} locale
119
+ * @returns {void}
120
+ */
39
121
  }, {
40
122
  key: "setLocale",
41
123
  value: function setLocale(locale) {
@@ -21,8 +21,33 @@ let Webchat = /*#__PURE__*/function () {
21
21
  _createClass(Webchat, [{
22
22
  key: "render",
23
23
  value: function render() {
24
+ this.applyBehaviourOverride();
24
25
  this.containerToAppendTo.appendChild(this.data.html);
25
26
  }
27
+ }, {
28
+ key: "applyBehaviourOverride",
29
+ value: function applyBehaviourOverride() {
30
+ if (!_core.Configuration.webchat.hasBehaviourOverride || !_core.Configuration.webchat.behaviour) return;
31
+ this.data.html.setAttribute('data-hellotext--webchat-behaviour-value', JSON.stringify(this.serializedBehaviour));
32
+ }
33
+ }, {
34
+ key: "serializedBehaviour",
35
+ get: function () {
36
+ const behaviour = _core.Configuration.webchat.behaviour;
37
+ return {
38
+ trigger: this.serializeTrigger(behaviour.trigger),
39
+ delay_seconds: behaviour.delaySeconds,
40
+ first_visit_only: behaviour.firstVisitOnly,
41
+ once_per_session: behaviour.oncePerSession
42
+ };
43
+ }
44
+ }, {
45
+ key: "serializeTrigger",
46
+ value: function serializeTrigger(trigger) {
47
+ if (trigger === 'onLoad') return 'on_load';
48
+ if (trigger === 'onClick') return 'on_click';
49
+ return trigger;
50
+ }
26
51
  }, {
27
52
  key: "containerToAppendTo",
28
53
  get: function () {
@@ -16,8 +16,33 @@ var Webchat = /*#__PURE__*/function () {
16
16
  _createClass(Webchat, [{
17
17
  key: "render",
18
18
  value: function render() {
19
+ this.applyBehaviourOverride();
19
20
  this.containerToAppendTo.appendChild(this.data.html);
20
21
  }
22
+ }, {
23
+ key: "applyBehaviourOverride",
24
+ value: function applyBehaviourOverride() {
25
+ if (!Configuration.webchat.hasBehaviourOverride || !Configuration.webchat.behaviour) return;
26
+ this.data.html.setAttribute('data-hellotext--webchat-behaviour-value', JSON.stringify(this.serializedBehaviour));
27
+ }
28
+ }, {
29
+ key: "serializedBehaviour",
30
+ get: function get() {
31
+ var behaviour = Configuration.webchat.behaviour;
32
+ return {
33
+ trigger: this.serializeTrigger(behaviour.trigger),
34
+ delay_seconds: behaviour.delaySeconds,
35
+ first_visit_only: behaviour.firstVisitOnly,
36
+ once_per_session: behaviour.oncePerSession
37
+ };
38
+ }
39
+ }, {
40
+ key: "serializeTrigger",
41
+ value: function serializeTrigger(trigger) {
42
+ if (trigger === 'onLoad') return 'on_load';
43
+ if (trigger === 'onClick') return 'on_click';
44
+ return trigger;
45
+ }
21
46
  }, {
22
47
  key: "containerToAppendTo",
23
48
  get: function get() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellotext/hellotext",
3
- "version": "2.3.8",
3
+ "version": "2.4.0",
4
4
  "description": "Hellotext JavaScript Client",
5
5
  "source": "src/index.js",
6
6
  "main": "lib/index.cjs",
@@ -16,6 +16,8 @@ class WebchatsAPI {
16
16
  url.searchParams.append(`style[${key}]`, value)
17
17
  })
18
18
 
19
+ this.appendWebchatOverrides(url)
20
+
19
21
  url.searchParams.append('placement', Configuration.webchat.placement)
20
22
 
21
23
  const response = await fetch(url, {
@@ -32,6 +34,21 @@ class WebchatsAPI {
32
34
 
33
35
  return new DOMParser().parseFromString(data.html, 'text/html').querySelector('article')
34
36
  }
37
+
38
+ static appendWebchatOverrides(url) {
39
+ const { appearance, whatsapp } = Configuration.webchat
40
+
41
+ this.appendIfSupplied(url, 'webchat[appearance][header][name]', appearance.header?.name)
42
+ this.appendIfSupplied(url, 'webchat[appearance][launcher][icon_url]', appearance.launcher?.iconUrl)
43
+ this.appendIfSupplied(url, 'webchat[handoff][identifier]', whatsapp.number)
44
+ this.appendIfSupplied(url, 'webchat[handoff][restrict_to_channel]', whatsapp.restrictToChannel)
45
+ }
46
+
47
+ static appendIfSupplied(url, key, value) {
48
+ if (value === undefined || value === null) return
49
+
50
+ url.searchParams.append(key, String(value))
51
+ }
35
52
  }
36
53
 
37
54
  export default WebchatsAPI