@subiz/widget-v4 4.1.202 → 4.1.204

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 (46) hide show
  1. package/api.md +1224 -0
  2. package/compiled_src/chatbox/ChatButton.js +19 -16
  3. package/compiled_src/chatbox/MessageInput.js +1 -0
  4. package/compiled_src/chatbox/main.js +28 -3
  5. package/compiled_src/lib.js +14 -0
  6. package/compiled_src/store/api.js +36 -4
  7. package/compiled_src/store/store.js +20 -4
  8. package/compiled_src/util/event.test.js +38 -0
  9. package/dist/19e1c4525c1.app.js +1 -0
  10. package/dist/{19d8a41ce33.chat.html → 19e1c4525c1.chat.html} +1 -1
  11. package/dist/19e1c4525c1.chat.js +1 -0
  12. package/dist/{19d8a41ce33.form.html → 19e1c4525c1.form.html} +1 -1
  13. package/dist/19e1c4525c1.form.js +1 -0
  14. package/dist/{19d8a41ce33.index.html → 19e1c4525c1.index.html} +1 -1
  15. package/dist/{19d8a41ce33.library.html → 19e1c4525c1.library.html} +1 -1
  16. package/dist/19e1c4525c1.library.js +1 -0
  17. package/dist/{19d8a41ce33.preview.html → 19e1c4525c1.preview.html} +1 -1
  18. package/dist/19e1c4525c1.preview.js +1 -0
  19. package/dist/19e1c4525c1.webview.js +1 -0
  20. package/dist/HASH +1 -1
  21. package/dist/screenshoot.js +104 -22
  22. package/package.json +8 -8
  23. package/src/chatbox/ChatButton.js +20 -15
  24. package/src/chatbox/MessageInput.js +1 -0
  25. package/src/chatbox/main.js +24 -4
  26. package/src/lib.js +14 -0
  27. package/src/store/api.js +41 -3
  28. package/src/store/store.js +28 -19
  29. package/src/util/event.test.js +31 -0
  30. package/dist/19d8a41ce33.app.js +0 -1
  31. package/dist/19d8a41ce33.chat.js +0 -1
  32. package/dist/19d8a41ce33.form.js +0 -1
  33. package/dist/19d8a41ce33.library.js +0 -1
  34. package/dist/19d8a41ce33.preview.js +0 -1
  35. package/dist/19d8a41ce33.webview.js +0 -1
  36. package/examples/track.js +0 -41
  37. /package/dist/{19d8a41ce33.127.js → 19e1c4525c1.127.js} +0 -0
  38. /package/dist/{19d8a41ce33.132.js → 19e1c4525c1.132.js} +0 -0
  39. /package/dist/{19d8a41ce33.185.js → 19e1c4525c1.185.js} +0 -0
  40. /package/dist/{19d8a41ce33.27.js → 19e1c4525c1.27.js} +0 -0
  41. /package/dist/{19d8a41ce33.278.js → 19e1c4525c1.278.js} +0 -0
  42. /package/dist/{19d8a41ce33.339.js → 19e1c4525c1.339.js} +0 -0
  43. /package/dist/{19d8a41ce33.459.js → 19e1c4525c1.459.js} +0 -0
  44. /package/dist/{19d8a41ce33.490.js → 19e1c4525c1.490.js} +0 -0
  45. /package/dist/{19d8a41ce33.74.js → 19e1c4525c1.74.js} +0 -0
  46. /package/dist/{19d8a41ce33.997.js → 19e1c4525c1.997.js} +0 -0
@@ -28,21 +28,8 @@ class ChatButton extends _common.Com {
28
28
  if (_index.default.get(ev, 'type') !== 'message_sent') return;
29
29
  let bytype = _index.default.get(ev, 'by.type');
30
30
  if (bytype !== 'system' && bytype !== 'agent' && bytype !== 'bot') return;
31
- let isquickreplies = false;
32
- _index.default.map(_index.default.get(ev, 'data.message.attachments', []), att => {
33
- if (!att) return;
34
- if (att.type === 'quick_replies') {
35
- isquickreplies = true;
36
- }
37
- });
38
- let format = _index.default.get(ev, 'data.message.format');
39
- let block = _index.default.get(ev, 'data.message.block');
40
- if (block || format == 'block') {
41
- if (_index.default.isBlockEmpty(block) && isquickreplies) return;
42
- } else {
43
- let message = _index.default.get(ev, 'data.message.text') || '';
44
- if (!message && isquickreplies) return;
45
- }
31
+ let message = _index.default.get(ev, 'data.message') || {};
32
+ if (_index.default.isEmptyMessage(message)) return;
46
33
  let screen = _index.default.get(this.props.store.matchLastview(), 'screen');
47
34
  let minimized = _index.default.get(this.props.store.matchLastview(), 'minimized');
48
35
  if (screen === 'widget') return;
@@ -401,6 +388,9 @@ class ChatButton extends _common.Com {
401
388
  imgurl = this.props.store.replaceFileUrl(imgurl);
402
389
  imgsrc = this.props.store.replaceFileUrl(imgsrc);
403
390
  maskurl = this.props.store.replaceFileUrl(maskurl);
391
+ imgurl = addVersionParam(imgurl);
392
+ imgsrc = addVersionParam(imgsrc);
393
+ maskurl = addVersionParam(maskurl);
404
394
  if (!imgurl && !maskurl) {
405
395
  whitebgcls += ' chat-button--white-bg--mask-only';
406
396
  imgcontainerstyle = `
@@ -532,4 +522,17 @@ function randomAgent(agentM) {
532
522
  }
533
523
  const Ms30Mins = 30 * 60 * 1000;
534
524
  const DEF_BG_URL = 'https://vcdn.subiz-cdn.com/file/bubble_11.svg?v=5';
535
- const DEF_BG = 'linear-gradient(280.16deg, #0053d3 22.03%, #0265ff 78.2%)';
525
+ const DEF_BG = 'linear-gradient(280.16deg, #0053d3 22.03%, #0265ff 78.2%)';
526
+ function addVersionParam(url, version = 8) {
527
+ if (!url) return url;
528
+ try {
529
+ const u = new URL(url);
530
+ u.searchParams.set('v', version);
531
+ return u.toString();
532
+ } catch (e) {
533
+ const [base, hash] = url.split('#');
534
+ const hasQuery = base.includes('?');
535
+ const newUrl = base + (hasQuery ? '&' : '?') + `v=${version}`;
536
+ return hash ? newUrl + '#' + hash : newUrl;
537
+ }
538
+ }
@@ -33,6 +33,7 @@ class MessageInput extends _common.Com {
33
33
  }, 500);
34
34
  this.resizeInput = _index.default.throttle(function () {
35
35
  const input = this.refMessageInput.current;
36
+ if (!input) return;
36
37
  input.style.setProperty('height', '1em', 'important');
37
38
  const height = Math.min(200, input.scrollHeight);
38
39
  input.style.setProperty('height', `${height}px`, 'important');
@@ -11,9 +11,16 @@ var _common = require("../common.js");
11
11
  var _preact = require("preact");
12
12
  var _css = _interopRequireDefault(require("./css.js"));
13
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
15
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
16
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
14
17
  class Main extends _common.Com {
15
18
  constructor(props) {
16
19
  super(props);
20
+ _defineProperty(this, "state", {
21
+ cssReady: false,
22
+ changing: false
23
+ });
17
24
  this.refButton = (0, _preact.createRef)();
18
25
  this.refWidget = (0, _preact.createRef)();
19
26
  }
@@ -41,9 +48,6 @@ class Main extends _common.Com {
41
48
  this.$cssStyleDiv.type = 'text/css';
42
49
  this.$cssStyleDiv.id = 'subiz-style-for-' + this.props.plugin.id;
43
50
  }
44
- this.setState({
45
- cssReady: false
46
- });
47
51
  this.checkExpand();
48
52
  this.props.store.onResetCSS(this, () => this.refreshCSS());
49
53
  this.props.store.onConvoEvent(this, ev => this.onConvoEvent(ev));
@@ -55,11 +59,32 @@ class Main extends _common.Com {
55
59
  });
56
60
  });
57
61
  this.refreshCSS();
62
+ let lastview = this.props.store.matchLastview() || {};
63
+ let cid = _index.default.get(lastview, 'opts.cid');
64
+ if (cid) {
65
+ this._last_cid = cid;
66
+ this.setState({
67
+ changing: true
68
+ }, () => {
69
+ this.props.store.fetchConvo(cid).then(() => {
70
+ let convo = this.props.store.matchConvo(cid);
71
+ if (cid != this._last_cid) return;
72
+ this.setState({
73
+ changing: false
74
+ });
75
+ if (!convo) return this.showWidget({});
76
+ });
77
+ });
78
+ }
58
79
  this.setState({
59
80
  cssReady: true
60
81
  });
61
82
  }
62
83
  render() {
84
+ if (this.state.changing) {
85
+ if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_changing_ready = _index.default.Date.now();
86
+ return null;
87
+ }
63
88
  if (!this.state.cssReady) {
64
89
  if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_css_not_ready = _index.default.Date.now();
65
90
  return null;
@@ -21,6 +21,11 @@ class Widget {
21
21
  _defineProperty(this, "setViewingProduct", p => this.store.linkProduct(p));
22
22
  _defineProperty(this, "getViewingProduct", () => this.store.getLinkedProduct());
23
23
  _defineProperty(this, "track", v => this.store.track(v));
24
+ _defineProperty(this, "event", async (type, payload, options) => {
25
+ await this.store.readyGate.entry();
26
+ return this.store.api.sendEvent(normalizeCdpEvent(type, payload, options));
27
+ });
28
+ _defineProperty(this, "pageview", v => this.store.sendPageview(v));
24
29
  this.impressionTokens = {};
25
30
  this.domGate = new _index.default.Gate();
26
31
  this.store = new _store.default(ApiURL, FileURL, RealtimeURL, inmem, fake);
@@ -364,5 +369,14 @@ class Widget {
364
369
  this.store.doNotStartBot();
365
370
  }
366
371
  }
372
+ function normalizeCdpEvent(type, payload, options) {
373
+ if (type && typeof type === 'object') return type;
374
+ let data = {
375
+ type: type
376
+ };
377
+ if (payload !== undefined) data.payload = payload;
378
+ if (options && typeof options === 'object') data = Object.assign({}, options, data);
379
+ return data;
380
+ }
367
381
  window.__sbz_WIDGET = Widget;
368
382
  var _default = exports.default = Widget;
@@ -170,12 +170,31 @@ class _default {
170
170
  _defineProperty(this, "time", _ => ajax.setBaseUrl(this.ApiURL).withCredentials(true).setParser('json').get('/time'));
171
171
  _defineProperty(this, "updateUser", data => this.apireq.post(`/accounts/${this.accid}/users/${this.uid}`, data));
172
172
  _defineProperty(this, "getUser", _ => this.apireq.get(`/accounts/${this.accid}/users/${this.uid}`));
173
- _defineProperty(this, "getAccountSetting", p => {
173
+ _defineProperty(this, "getAccountSetting", async p => {
174
174
  let href = _index.default.get(document, 'location.href');
175
+ let res = {};
175
176
  if (p && p.bot_id) {
176
- return this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`);
177
+ res = await this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`);
178
+ } else {
179
+ res = await this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`);
177
180
  }
178
- return this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`);
181
+ if (res.error) return res;
182
+ let plugins = _index.default.get(res, 'body.plugins') || [];
183
+ _index.default.map(plugins, plugin => {
184
+ if (plugin.type === 'popup') {
185
+ let pages = _index.default.get(plugin, 'popup.pages') || [];
186
+ _index.default.map(pages, page => {
187
+ _index.default.map(page.components, com => {
188
+ if (com.type === 'image') {
189
+ let url = _index.default.get(com, 'image.url');
190
+ _index.default.set(com, 'image.url', fallbackGCSUrl(url));
191
+ }
192
+ });
193
+ });
194
+ }
195
+ });
196
+ _index.default.set(res, 'body.plugins', plugins);
197
+ return res;
179
198
  });
180
199
  _defineProperty(this, "sendImpression", impression => this.apireq.post(`/accounts/${this.accid}/campaigns/${impression.campaign_id}/impressions`, impression));
181
200
  _defineProperty(this, "sendConversion", conversion => this.apireq.post(`/accounts/${this.accid}/campaigns/${conversion.campaign_id}/conversions`, conversion));
@@ -361,4 +380,17 @@ class _default {
361
380
  });
362
381
  }
363
382
  }
364
- exports.default = _default;
383
+ exports.default = _default;
384
+ function fallbackGCSUrl(url) {
385
+ try {
386
+ const u = new URL(url);
387
+ const isGCS = u.hostname === 'storage.googleapis.com';
388
+ const isSubizBucket = u.pathname.startsWith('/public-gcs.subiz-cdn.com/');
389
+ if (isGCS && isSubizBucket) {
390
+ return `https://${u.pathname.slice(1)}`;
391
+ }
392
+ return url;
393
+ } catch (e) {
394
+ return url;
395
+ }
396
+ }
@@ -176,14 +176,14 @@ class Store {
176
176
  _defineProperty(this, "checkFormToken", (accid, token) => this.api.checkFormToken(accid, token));
177
177
  _defineProperty(this, "submitForm2", (accid, token, data) => this.api.submitForm2(accid, token, data));
178
178
  _defineProperty(this, "sendPresence", _index.default.throttle(async () => {
179
+ if (!this._track_page_view) return;
179
180
  if (this._die) return dieErr;
180
181
  await this.readyGate.entry();
181
182
  if (!_index.default.get(this.cache.match('user'), 'id')) return;
182
183
  if (_index.default.isUserBanned(this.cache.match('user'))) return;
183
- if (!this._track_page_view) return;
184
184
  let hasfocus = this.browserVisibility === 'visible' && document.hasFocus();
185
185
  if (!hasfocus) return this.api.sendLostFocus();
186
- this.api.sendContentView(this.device, location.href, document.title, this._currentViewingProduct.id, this._currentViewingProduct.source_id, this._currentViewingProduct.sku);
186
+ this.sendPageview();
187
187
  }, 1000, {
188
188
  leading: false
189
189
  }));
@@ -277,6 +277,13 @@ class Store {
277
277
  this.sendPresence();
278
278
  });
279
279
  window.addEventListener('beforeunload', () => this.api.sendLostFocus());
280
+ this._lastPresenceURL = window.location.href;
281
+ this._urlCheckInterval = _index.default.setInterval(() => {
282
+ if (this._die) return _index.default.clearInterval(this._urlCheckInterval);
283
+ if (this._lastPresenceURL === window.location.href) return;
284
+ this._lastPresenceURL = window.location.href;
285
+ this.sendPresence();
286
+ }, 2_000);
280
287
  this.doNotStartBot = () => {
281
288
  this._donotstartbot = true;
282
289
  };
@@ -798,12 +805,20 @@ class Store {
798
805
  this.cache.put('payment_methods', pms);
799
806
  this.pubsub.publish('account');
800
807
  }
808
+ async sendPageview(p) {
809
+ if (!p) p = {};
810
+ let device = Object.assign({}, this.device);
811
+ if (p.referrer) device.source_referrer = p.referrer;
812
+ device.page_url = p.url || location.href;
813
+ device.page_title = p.title || document.title;
814
+ return this.api.sendContentView(device, p.url || location.href, p.title || document.title, this._currentViewingProduct.id, this._currentViewingProduct.source_id, this._currentViewingProduct.sku);
815
+ }
801
816
  async track(e) {
802
817
  if (!e) {
803
- let out = await this.api.sendContentView(this.device, location.href, document.title, this._currentViewingProduct.id, this._currentViewingProduct.source_id, this._currentViewingProduct.sku);
818
+ let out = await this.sendPageview();
804
819
  let traffic_source = _index.default.get(out, 'body.by.device.source', '');
805
820
  if (traffic_source) this.kv.put('traffic_source', traffic_source);
806
- return;
821
+ return out;
807
822
  }
808
823
  if (typeof e === 'object') {
809
824
  if (!e.data) e.data = {};
@@ -1306,6 +1321,7 @@ class Store {
1306
1321
  this._die = true;
1307
1322
  this.clearBrowserData();
1308
1323
  _index.default.clearInterval(this._seenInterval);
1324
+ _index.default.clearInterval(this._urlCheckInterval);
1309
1325
  if (this.realtime) this.realtime.stop();
1310
1326
  this.readyGate.close();
1311
1327
  window.removeEventListener('blur', this.sendPresence);
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ var test = require('tape');
4
+ var {
5
+ normalizeCdpEvent
6
+ } = require('./event.js');
7
+ test('normalize cdp event new signature', t => {
8
+ t.deepEqual(normalizeCdpEvent('content_viewed', {
9
+ url: 'https://example.com/products/pd2345',
10
+ title: 'Bàn phím cơ không dây'
11
+ }, {
12
+ event_source_id: 'evt_1234'
13
+ }), {
14
+ type: 'content_viewed',
15
+ payload: {
16
+ url: 'https://example.com/products/pd2345',
17
+ title: 'Bàn phím cơ không dây'
18
+ },
19
+ event_source_id: 'evt_1234'
20
+ });
21
+ t.end();
22
+ });
23
+ test('normalize cdp event without payload', t => {
24
+ t.deepEqual(normalizeCdpEvent('login'), {
25
+ type: 'login'
26
+ });
27
+ t.end();
28
+ });
29
+ test('normalize cdp event keeps old object signature', t => {
30
+ let event = {
31
+ type: 'product_viewed',
32
+ payload: {
33
+ id: 'pd2345'
34
+ }
35
+ };
36
+ t.equal(normalizeCdpEvent(event), event);
37
+ t.end();
38
+ });