@subiz/widget-v4 4.1.202 → 4.1.203

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 (37) hide show
  1. package/api.md +1284 -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 +15 -0
  6. package/compiled_src/store/api.js +36 -4
  7. package/dist/{19d8a41ce33.app.js → 19df158c2ea.app.js} +1 -1
  8. package/dist/{19d8a41ce33.chat.html → 19df158c2ea.chat.html} +1 -1
  9. package/dist/{19d8a41ce33.chat.js → 19df158c2ea.chat.js} +1 -1
  10. package/dist/{19d8a41ce33.form.html → 19df158c2ea.form.html} +1 -1
  11. package/dist/19df158c2ea.form.js +1 -0
  12. package/dist/{19d8a41ce33.index.html → 19df158c2ea.index.html} +1 -1
  13. package/dist/{19d8a41ce33.library.html → 19df158c2ea.library.html} +1 -1
  14. package/dist/{19d8a41ce33.library.js → 19df158c2ea.library.js} +1 -1
  15. package/dist/{19d8a41ce33.preview.html → 19df158c2ea.preview.html} +1 -1
  16. package/dist/{19d8a41ce33.preview.js → 19df158c2ea.preview.js} +1 -1
  17. package/dist/{19d8a41ce33.webview.js → 19df158c2ea.webview.js} +1 -1
  18. package/dist/HASH +1 -1
  19. package/dist/screenshoot.js +54 -19
  20. package/package.json +8 -8
  21. package/src/chatbox/ChatButton.js +20 -15
  22. package/src/chatbox/MessageInput.js +1 -0
  23. package/src/chatbox/main.js +24 -4
  24. package/src/lib.js +15 -0
  25. package/src/store/api.js +41 -3
  26. package/dist/19d8a41ce33.form.js +0 -1
  27. package/examples/track.js +0 -41
  28. /package/dist/{19d8a41ce33.127.js → 19df158c2ea.127.js} +0 -0
  29. /package/dist/{19d8a41ce33.132.js → 19df158c2ea.132.js} +0 -0
  30. /package/dist/{19d8a41ce33.185.js → 19df158c2ea.185.js} +0 -0
  31. /package/dist/{19d8a41ce33.27.js → 19df158c2ea.27.js} +0 -0
  32. /package/dist/{19d8a41ce33.278.js → 19df158c2ea.278.js} +0 -0
  33. /package/dist/{19d8a41ce33.339.js → 19df158c2ea.339.js} +0 -0
  34. /package/dist/{19d8a41ce33.459.js → 19df158c2ea.459.js} +0 -0
  35. /package/dist/{19d8a41ce33.490.js → 19df158c2ea.490.js} +0 -0
  36. /package/dist/{19d8a41ce33.74.js → 19df158c2ea.74.js} +0 -0
  37. /package/dist/{19d8a41ce33.997.js → 19df158c2ea.997.js} +0 -0
package/dist/HASH CHANGED
@@ -1 +1 @@
1
- 19d8a41ce33
1
+ 19df158c2ea
@@ -4389,12 +4389,31 @@ let trackResponseFn = (param, done) => {
4389
4389
  _defineProperty(this, "time", _ => ajax.setBaseUrl(this.ApiURL).withCredentials(true).setParser('json').get('/time'));
4390
4390
  _defineProperty(this, "updateUser", data => this.apireq.post(`/accounts/${this.accid}/users/${this.uid}`, data));
4391
4391
  _defineProperty(this, "getUser", _ => this.apireq.get(`/accounts/${this.accid}/users/${this.uid}`));
4392
- _defineProperty(this, "getAccountSetting", p => {
4392
+ _defineProperty(this, "getAccountSetting", async p => {
4393
4393
  let href = util/* default */.A.get(document, 'location.href');
4394
+ let res = {};
4394
4395
  if (p && p.bot_id) {
4395
- return this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`);
4396
- }
4397
- return this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`);
4396
+ res = await this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`);
4397
+ } else {
4398
+ res = await this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`);
4399
+ }
4400
+ if (res.error) return res;
4401
+ let plugins = util/* default */.A.get(res, 'body.plugins') || [];
4402
+ util/* default */.A.map(plugins, plugin => {
4403
+ if (plugin.type === 'popup') {
4404
+ let pages = util/* default */.A.get(plugin, 'popup.pages') || [];
4405
+ util/* default */.A.map(pages, page => {
4406
+ util/* default */.A.map(page.components, com => {
4407
+ if (com.type === 'image') {
4408
+ let url = util/* default */.A.get(com, 'image.url');
4409
+ util/* default */.A.set(com, 'image.url', fallbackGCSUrl(url));
4410
+ }
4411
+ });
4412
+ });
4413
+ }
4414
+ });
4415
+ util/* default */.A.set(res, 'body.plugins', plugins);
4416
+ return res;
4398
4417
  });
4399
4418
  _defineProperty(this, "sendImpression", impression => this.apireq.post(`/accounts/${this.accid}/campaigns/${impression.campaign_id}/impressions`, impression));
4400
4419
  _defineProperty(this, "sendConversion", conversion => this.apireq.post(`/accounts/${this.accid}/campaigns/${conversion.campaign_id}/conversions`, conversion));
@@ -4580,6 +4599,19 @@ let trackResponseFn = (param, done) => {
4580
4599
  });
4581
4600
  }
4582
4601
  });
4602
+ function fallbackGCSUrl(url) {
4603
+ try {
4604
+ const u = new URL(url);
4605
+ const isGCS = u.hostname === 'storage.googleapis.com';
4606
+ const isSubizBucket = u.pathname.startsWith('/public-gcs.subiz-cdn.com/');
4607
+ if (isGCS && isSubizBucket) {
4608
+ return `https://${u.pathname.slice(1)}`;
4609
+ }
4610
+ return url;
4611
+ } catch (e) {
4612
+ return url;
4613
+ }
4614
+ }
4583
4615
  ;// ./src/store/lsdb.js
4584
4616
  let memlocalStorage = __webpack_require__(450);
4585
4617
 
@@ -6853,21 +6885,8 @@ class ChatButton extends common/* Com */.Mw {
6853
6885
  if (util/* default */.A.get(ev, 'type') !== 'message_sent') return;
6854
6886
  let bytype = util/* default */.A.get(ev, 'by.type');
6855
6887
  if (bytype !== 'system' && bytype !== 'agent' && bytype !== 'bot') return;
6856
- let isquickreplies = false;
6857
- util/* default */.A.map(util/* default */.A.get(ev, 'data.message.attachments', []), att => {
6858
- if (!att) return;
6859
- if (att.type === 'quick_replies') {
6860
- isquickreplies = true;
6861
- }
6862
- });
6863
- let format = util/* default */.A.get(ev, 'data.message.format');
6864
- let block = util/* default */.A.get(ev, 'data.message.block');
6865
- if (block || format == 'block') {
6866
- if (util/* default */.A.isBlockEmpty(block) && isquickreplies) return;
6867
- } else {
6868
- let message = util/* default */.A.get(ev, 'data.message.text') || '';
6869
- if (!message && isquickreplies) return;
6870
- }
6888
+ let message = util/* default */.A.get(ev, 'data.message') || {};
6889
+ if (util/* default */.A.isEmptyMessage(message)) return;
6871
6890
  let screen = util/* default */.A.get(this.props.store.matchLastview(), 'screen');
6872
6891
  let minimized = util/* default */.A.get(this.props.store.matchLastview(), 'minimized');
6873
6892
  if (screen === 'widget') return;
@@ -7226,6 +7245,9 @@ class ChatButton extends common/* Com */.Mw {
7226
7245
  imgurl = this.props.store.replaceFileUrl(imgurl);
7227
7246
  imgsrc = this.props.store.replaceFileUrl(imgsrc);
7228
7247
  maskurl = this.props.store.replaceFileUrl(maskurl);
7248
+ imgurl = addVersionParam(imgurl);
7249
+ imgsrc = addVersionParam(imgsrc);
7250
+ maskurl = addVersionParam(maskurl);
7229
7251
  if (!imgurl && !maskurl) {
7230
7252
  whitebgcls += ' chat-button--white-bg--mask-only';
7231
7253
  imgcontainerstyle = `
@@ -7357,6 +7379,19 @@ function randomAgent(agentM) {
7357
7379
  const Ms30Mins = 30 * 60 * 1000;
7358
7380
  const DEF_BG_URL = 'https://vcdn.subiz-cdn.com/file/bubble_11.svg?v=5';
7359
7381
  const DEF_BG = 'linear-gradient(280.16deg, #0053d3 22.03%, #0265ff 78.2%)';
7382
+ function addVersionParam(url, version = 8) {
7383
+ if (!url) return url;
7384
+ try {
7385
+ const u = new URL(url);
7386
+ u.searchParams.set('v', version);
7387
+ return u.toString();
7388
+ } catch (e) {
7389
+ const [base, hash] = url.split('#');
7390
+ const hasQuery = base.includes('?');
7391
+ const newUrl = base + (hasQuery ? '&' : '?') + `v=${version}`;
7392
+ return hash ? newUrl + '#' + hash : newUrl;
7393
+ }
7394
+ }
7360
7395
  ;// ./src/chatbox/PoweredBy.js
7361
7396
  var logo = __webpack_require__(9529);
7362
7397
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/widget-v4",
3
- "version": "4.1.202",
3
+ "version": "4.1.203",
4
4
  "main": "./compiled_src/lib.js",
5
5
  "scripts": {
6
6
  "dev": "npx webpack serve --config webpack.dev.js",
@@ -11,7 +11,7 @@
11
11
  "dependencies": {
12
12
  "@subiz/ajax": "^3.0.22",
13
13
  "@subiz/flow": "^1.1.0",
14
- "@subiz/wsclient": "^4.0.34",
14
+ "@subiz/wsclient": "^4.0.35",
15
15
  "cookie_js": "1.4.2",
16
16
  "core-js": "^3.49.0",
17
17
  "css-loader": "5.2.7",
@@ -26,14 +26,14 @@
26
26
  "@babel/core": "^7.29.0",
27
27
  "@babel/plugin-proposal-class-properties": "^7.18.6",
28
28
  "@babel/plugin-transform-react-jsx": "^7.28.6",
29
- "@babel/preset-env": "^7.29.2",
29
+ "@babel/preset-env": "^7.29.5",
30
30
  "babel-loader": "^10.1.1",
31
31
  "babel-plugin-syntax-jsx": "^6.18.0",
32
- "html-webpack-plugin": "^5.6.6",
33
- "puppeteer": "^24.40.0",
34
- "webpack": "^5.105.4",
35
- "webpack-bundle-analyzer": "^5.2.0",
32
+ "html-webpack-plugin": "^5.6.7",
33
+ "puppeteer": "^24.43.1",
34
+ "webpack": "^5.106.2",
35
+ "webpack-bundle-analyzer": "^5.3.0",
36
36
  "webpack-cli": "^7.0.2",
37
- "webpack-dev-server": "^5.2.3"
37
+ "webpack-dev-server": "^5.2.4"
38
38
  }
39
39
  }
@@ -27,21 +27,8 @@ export default class ChatButton extends Com {
27
27
  let bytype = sb.get(ev, 'by.type')
28
28
  if (bytype !== 'system' && bytype !== 'agent' && bytype !== 'bot') return
29
29
 
30
- let isquickreplies = false
31
- sb.map(sb.get(ev, 'data.message.attachments', []), (att) => {
32
- if (!att) return
33
- if (att.type === 'quick_replies') {
34
- isquickreplies = true
35
- }
36
- })
37
- let format = sb.get(ev, 'data.message.format')
38
- let block = sb.get(ev, 'data.message.block')
39
- if (block || format == 'block') {
40
- if (sb.isBlockEmpty(block) && isquickreplies) return
41
- } else {
42
- let message = sb.get(ev, 'data.message.text') || ''
43
- if (!message && isquickreplies) return
44
- }
30
+ let message = sb.get(ev, 'data.message') || {}
31
+ if (sb.isEmptyMessage(message)) return
45
32
  let screen = sb.get(this.props.store.matchLastview(), 'screen')
46
33
  let minimized = sb.get(this.props.store.matchLastview(), 'minimized')
47
34
  if (screen === 'widget') return
@@ -453,6 +440,9 @@ export default class ChatButton extends Com {
453
440
  imgurl = this.props.store.replaceFileUrl(imgurl)
454
441
  imgsrc = this.props.store.replaceFileUrl(imgsrc)
455
442
  maskurl = this.props.store.replaceFileUrl(maskurl)
443
+ imgurl = addVersionParam(imgurl)
444
+ imgsrc = addVersionParam(imgsrc)
445
+ maskurl = addVersionParam(maskurl)
456
446
 
457
447
  if (!imgurl && !maskurl) {
458
448
  whitebgcls += ' chat-button--white-bg--mask-only'
@@ -595,3 +585,18 @@ const Ms30Mins = 30 * 60 * 1000
595
585
  // v=5 trick to clear cache
596
586
  const DEF_BG_URL = 'https://vcdn.subiz-cdn.com/file/bubble_11.svg?v=5'
597
587
  const DEF_BG = 'linear-gradient(280.16deg, #0053d3 22.03%, #0265ff 78.2%)'
588
+
589
+ function addVersionParam(url, version = 8) {
590
+ if (!url) return url
591
+ try {
592
+ const u = new URL(url)
593
+ u.searchParams.set('v', version)
594
+ return u.toString()
595
+ } catch (e) {
596
+ // fallback nếu url không hợp lệ hoàn toàn
597
+ const [base, hash] = url.split('#')
598
+ const hasQuery = base.includes('?')
599
+ const newUrl = base + (hasQuery ? '&' : '?') + `v=${version}`
600
+ return hash ? newUrl + '#' + hash : newUrl
601
+ }
602
+ }
@@ -25,6 +25,7 @@ export default class MessageInput extends Com {
25
25
  this.resizeInput = sb.throttle(function () {
26
26
  // TODO: ctrl+A then press backspace dont reset size rightaway
27
27
  const input = this.refMessageInput.current
28
+ if (!input) return
28
29
  input.style.setProperty('height', '1em', 'important')
29
30
  const height = Math.min(200, input.scrollHeight)
30
31
  input.style.setProperty('height', `${height}px`, 'important')
@@ -17,6 +17,11 @@ export default class Main extends Com {
17
17
  this.refWidget = createRef()
18
18
  }
19
19
 
20
+ state = {
21
+ cssReady: false,
22
+ changing: false,
23
+ }
24
+
20
25
  refreshCSS() {
21
26
  // make sure you are still alive
22
27
  let plugins = this.props.store.matchPlugin()
@@ -45,10 +50,6 @@ export default class Main extends Com {
45
50
  this.$cssStyleDiv.id = 'subiz-style-for-' + this.props.plugin.id
46
51
  }
47
52
 
48
- this.setState({
49
- cssReady: false,
50
- })
51
-
52
53
  this.checkExpand()
53
54
  this.props.store.onResetCSS(this, () => this.refreshCSS())
54
55
  this.props.store.onConvoEvent(this, (ev) => this.onConvoEvent(ev))
@@ -60,10 +61,29 @@ export default class Main extends Com {
60
61
  })
61
62
  })
62
63
  this.refreshCSS()
64
+
65
+ let lastview = this.props.store.matchLastview() || {}
66
+ let cid = sb.get(lastview, 'opts.cid')
67
+ if (cid) {
68
+ this._last_cid = cid
69
+ this.setState({changing: true}, () => {
70
+ this.props.store.fetchConvo(cid).then(() => {
71
+ let convo = this.props.store.matchConvo(cid)
72
+ if (cid != this._last_cid) return // outdated
73
+ this.setState({changing: false})
74
+ if (!convo) return this.showWidget({}) // invalid convo, must redirect
75
+ })
76
+ })
77
+ }
78
+
63
79
  this.setState({cssReady: true})
64
80
  }
65
81
 
66
82
  render() {
83
+ if (this.state.changing) {
84
+ if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_changing_ready = sb.Date.now()
85
+ return null
86
+ }
67
87
  if (!this.state.cssReady) {
68
88
  if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_css_not_ready = sb.Date.now()
69
89
  return null
package/src/lib.js CHANGED
@@ -317,6 +317,21 @@ class Widget {
317
317
  getViewingProduct = () => this.store.getLinkedProduct()
318
318
 
319
319
  track = (v) => this.store.track(v)
320
+ event = async (v) => {
321
+ await this.store.readyGate.entry()
322
+ return this.store.api.sendEvent(v)
323
+ }
324
+ pageview = (v) => {
325
+ v = v || {}
326
+ return this.event({
327
+ type: 'content_viewed',
328
+ payload: {
329
+ url: v.url || location.href,
330
+ title: v.title || document.title,
331
+ referrer: v.referrer || document.referrer,
332
+ },
333
+ })
334
+ }
320
335
 
321
336
  async setLocale(locale) {
322
337
  await this.domGate.entry()
package/src/store/api.js CHANGED
@@ -394,12 +394,33 @@ export default class {
394
394
  updateUser = (data) => this.apireq.post(`/accounts/${this.accid}/users/${this.uid}`, data)
395
395
 
396
396
  getUser = (_) => this.apireq.get(`/accounts/${this.accid}/users/${this.uid}`)
397
- getAccountSetting = (p) => {
397
+ getAccountSetting = async (p) => {
398
398
  let href = sb.get(document, 'location.href') // send full href, this could be used to select which bot (ai-agent) should be returned
399
+ let res = {}
399
400
  if (p && p.bot_id) {
400
- return this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`)
401
+ res = await this.apireq.addQuery('url', href).addQuery('bot_id', p.bot_id).get(`/accounts/${this.accid}/settings`)
402
+ } else {
403
+ res = await this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`)
401
404
  }
402
- return this.apireq.addQuery('url', href).get(`/accounts/${this.accid}/settings`)
405
+ if (res.error) return res
406
+
407
+ // fix image error image url link in popup
408
+ let plugins = sb.get(res, 'body.plugins') || []
409
+ sb.map(plugins, (plugin) => {
410
+ if (plugin.type === 'popup') {
411
+ let pages = sb.get(plugin, 'popup.pages') || []
412
+ sb.map(pages, (page) => {
413
+ sb.map(page.components, (com) => {
414
+ if (com.type === 'image') {
415
+ let url = sb.get(com, 'image.url')
416
+ sb.set(com, 'image.url', fallbackGCSUrl(url))
417
+ }
418
+ })
419
+ })
420
+ }
421
+ })
422
+ sb.set(res, 'body.plugins', plugins)
423
+ return res
403
424
  }
404
425
 
405
426
  sendImpression = (impression) =>
@@ -432,3 +453,20 @@ export default class {
432
453
  suggest_address = (keyword) => this.apireq.setQuery({keyword: keyword}).get(`/accounts/${this.accid}/addresses`)
433
454
  create_ticket = (ticket) => this.apireq.post(`/accounts/${this.accid}/tickets`, ticket)
434
455
  }
456
+
457
+ function fallbackGCSUrl(url) {
458
+ try {
459
+ const u = new URL(url)
460
+
461
+ const isGCS = u.hostname === 'storage.googleapis.com'
462
+ const isSubizBucket = u.pathname.startsWith('/public-gcs.subiz-cdn.com/')
463
+
464
+ if (isGCS && isSubizBucket) {
465
+ return `https://${u.pathname.slice(1)}`
466
+ }
467
+
468
+ return url
469
+ } catch (e) {
470
+ return url
471
+ }
472
+ }