@subiz/widget-v4 4.0.85 → 4.0.88

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 (53) hide show
  1. package/.prettierrc.js +1 -1
  2. package/compiled_src/chatbox/AgentsAvatar.js +20 -3
  3. package/compiled_src/chatbox/ChatButton.js +11 -8
  4. package/compiled_src/chatbox/Event.js +12 -0
  5. package/compiled_src/chatbox/Events.js +1 -0
  6. package/compiled_src/chatbox/MessageInput.js +6 -0
  7. package/compiled_src/chatbox/Widget.js +41 -37
  8. package/compiled_src/chatbox/main.js +10 -0
  9. package/compiled_src/popup/popup.js +14 -2
  10. package/compiled_src/store/store.js +24 -40
  11. package/compiled_src/util/common.js +10 -10
  12. package/dist/132.js +105 -48
  13. package/dist/182ee177a49.132.js +1 -0
  14. package/dist/{181a9b734bb.178.js → 182ee177a49.178.js} +0 -0
  15. package/dist/{181a9b734bb.213.js → 182ee177a49.213.js} +1 -1
  16. package/dist/{181a9b734bb.335.js → 182ee177a49.335.js} +0 -0
  17. package/dist/{181a9b734bb.362.js → 182ee177a49.362.js} +1 -1
  18. package/dist/182ee177a49.441.js +1 -0
  19. package/dist/{181a9b734bb.605.js → 182ee177a49.605.js} +0 -0
  20. package/dist/{181a9b734bb.678.js → 182ee177a49.678.js} +0 -0
  21. package/dist/{181a9b734bb.782.js → 182ee177a49.782.js} +1 -1
  22. package/dist/182ee177a49.app.js +1 -0
  23. package/dist/{181a9b734bb.index.html → 182ee177a49.index.html} +2 -2
  24. package/dist/{181a9b734bb.library.html → 182ee177a49.library.html} +2 -2
  25. package/dist/182ee177a49.library.js +1 -0
  26. package/dist/{181a9b734bb.preview.html → 182ee177a49.preview.html} +1 -1
  27. package/dist/182ee177a49.preview.js +1 -0
  28. package/dist/182ee177a49.screenshoot.js +1 -0
  29. package/dist/213.js +18 -1
  30. package/dist/362.js +1 -1
  31. package/dist/441.js +14 -1
  32. package/dist/782.js +1 -1
  33. package/dist/HASH +1 -1
  34. package/dist/screenshoot.html +1 -1
  35. package/dist/screenshoot.js +36 -56
  36. package/index.html +1 -1
  37. package/package.json +11 -11
  38. package/src/chatbox/AgentsAvatar.js +32 -10
  39. package/src/chatbox/ChatButton.js +11 -4
  40. package/src/chatbox/Event.js +23 -4
  41. package/src/chatbox/Events.js +3 -1
  42. package/src/chatbox/MessageInput.js +14 -5
  43. package/src/chatbox/Widget.js +10 -9
  44. package/src/chatbox/main.js +8 -1
  45. package/src/popup/popup.js +14 -1
  46. package/src/store/store.js +24 -36
  47. package/src/util/common.js +16 -19
  48. package/dist/181a9b734bb.132.js +0 -1
  49. package/dist/181a9b734bb.441.js +0 -1
  50. package/dist/181a9b734bb.app.js +0 -1
  51. package/dist/181a9b734bb.library.js +0 -1
  52. package/dist/181a9b734bb.preview.js +0 -1
  53. package/dist/181a9b734bb.screenshoot.js +0 -1
@@ -18,7 +18,7 @@ const defaultAvatar = 'https://file-subiz.com/fiqoahedjbgwclpouoml-avatar_defaul
18
18
  import Spinner from './spinner.js'
19
19
  import Time from './time.js'
20
20
  import {Com} from '../common.js'
21
- import {h} from 'preact'
21
+ import {h, createRef} from 'preact'
22
22
 
23
23
  // ['cid', 'view', 'isShow'], // view: chat, list
24
24
  export default class Widget extends Com {
@@ -36,6 +36,7 @@ export default class Widget extends Com {
36
36
  this.props.store.onUpdate(this, (_) => this.forceUpdate())
37
37
  }
38
38
 
39
+ msgInput = createRef()
39
40
  componentDidMount() {
40
41
  if (!this.props.store.isMobile()) this.focusInput()
41
42
  }
@@ -484,7 +485,7 @@ export default class Widget extends Com {
484
485
 
485
486
  blur() {
486
487
  if (this.props.store.isPreview) return
487
- var $input = this.msgInput
488
+ var $input = this.msgInput.current
488
489
  if (!$input) return
489
490
  setTimeout(() => $input && $input.blur())
490
491
  setTimeout(() => $input && $input.blur(), 300) // force lose focus
@@ -512,7 +513,7 @@ export default class Widget extends Com {
512
513
  return
513
514
  }
514
515
 
515
- var $input = this.msgInput
516
+ var $input = this.msgInput.current
516
517
  if (!$input) return
517
518
  setTimeout(() => $input.focus())
518
519
  setTimeout(() => $input.focus(), 300) // force focus
@@ -524,7 +525,7 @@ export default class Widget extends Com {
524
525
  this.focusInput()
525
526
  }
526
527
 
527
- async sendMessage(message) {
528
+ sendMessage = async (message) => {
528
529
  let text = message.text
529
530
  if (!this.props.cid) {
530
531
  this.creating = true
@@ -554,9 +555,9 @@ export default class Widget extends Com {
554
555
  let $input = (
555
556
  <MessageInput
556
557
  store={this.props.store}
557
- ref={(ref) => (this.msgInput = ref)}
558
+ ref={this.msgInput}
558
559
  cid={this.props.cid}
559
- onSend={(e) => this.sendMessage(e)}
560
+ onSend={this.sendMessage}
560
561
  t={this.props.t}
561
562
  />
562
563
  )
@@ -578,6 +579,7 @@ export default class Widget extends Com {
578
579
  isShow={this.props.isShow}
579
580
  onLink={this.onLink}
580
581
  store={this.props.store}
582
+ chatbox={this.props.plugin.chatbox || {}}
581
583
  onFormSubmit={(e) => this.onEventFormSubmit(e)}
582
584
  ref={(ref) => (this.events = ref)}
583
585
  cid={this.props.cid}
@@ -679,6 +681,7 @@ export default class Widget extends Com {
679
681
  }
680
682
 
681
683
  renderConvoSummary(convo) {
684
+ let accountSetting = this.props.plugin.chatbox || {}
682
685
  let agentM = this.props.store.matchAgent('*')
683
686
 
684
687
  let ags = sb.filter(convo.members, (m) => {
@@ -688,9 +691,8 @@ export default class Widget extends Com {
688
691
  agentids = agentids || sb.agentsOfConvo(convo)[0]
689
692
 
690
693
  let agents = sb.map(agentids, (id) => agentM[id] || {avatar_url: defaultAvatar, fullname: 'Offline Agent'})
691
-
692
694
  var name = sb.each(agents, (ag) => ag.fullname).join(', ')
693
- if (!name) name = this.props.store.matchAccount().name
695
+ if (accountSetting.hide_agent_profile || !name) name = this.props.store.matchAccount().name
694
696
  if (!name) name = this.props.t('agent')
695
697
 
696
698
  var $you = null
@@ -699,7 +701,6 @@ export default class Widget extends Com {
699
701
  }
700
702
 
701
703
  let seen = sb.isConvoSeen(convo, this.props.store.matchUser().id)
702
-
703
704
  var lastmsg = this.renderMessagePreview(convo.last_message_sent || {data: {message: sb.get(convo, 'last_message')}})
704
705
 
705
706
  var time =
@@ -125,8 +125,15 @@ export default class Main extends Com {
125
125
  }
126
126
  p = p || {}
127
127
 
128
- if (this.props.store.isMobile()) modifyViewport()
128
+ if (!p.view && !p.cid) {
129
+ let convoM = this.props.store.matchConvo('*')
130
+ let redconvo = sb.find(convoM, (convo) => !sb.isConvoSeen(convo, this.props.store.matchUser().id))
131
+ // try to show first convo
132
+ p.cid = sb.get(redconvo, 'id', sb.get(convoM, '0.id'))
133
+ p.view = 'chat'
134
+ }
129
135
 
136
+ if (this.props.store.isMobile()) modifyViewport()
130
137
  this.setState({widgetConvoId: p.cid, widgetView: p.view})
131
138
  this.props.store.setIsOpen(true)
132
139
 
@@ -215,12 +215,25 @@ export default class Popup extends Com {
215
215
 
216
216
  let user = sb.cloneDeep(this.props.store.matchUser())
217
217
  let is_lead = false
218
+
219
+ // modified pairs to convert data of multiple-choice value ['khu_vuc', '1'], ['khu_vuc', '2'] => ['khu_vuc', '1,2']
220
+ let modifiedPairs = {}
218
221
  for (var pair of formData.entries()) {
222
+ if (modifiedPairs[pair[0]]) {
223
+ let currentValue = sb.get(modifiedPairs, `${pair[0]}.1`, '')
224
+ currentValue += `,${pair[1]}`
225
+ sb.set(modifiedPairs, `${pair[0]}.1`, currentValue)
226
+ } else {
227
+ modifiedPairs[pair[0]] = [pair[0], pair[1]]
228
+ }
229
+ }
230
+
231
+ for (const [_, pair] of Object.entries(modifiedPairs)) {
219
232
  let page = sb.get(this.props.plugin.popup, `pages.${this.getPageIndex()}`)
220
233
  let form = sb.find(page.components, (com) => com.type === 'form')
221
234
  let fields = sb.get(form, 'form.fields', [])
222
235
 
223
- let field = sb.find(fields, (field) => field.key === pair[0])
236
+ let field = sb.find(fields, (field) => field.key === pair[0]) || {}
224
237
  if (!field.type) return
225
238
 
226
239
  summitFields.push({key: pair[0], type: field.type, value: sb.stringify(pair[1])})
@@ -13,7 +13,7 @@ cookie.defaults.expires = 3650 // 10 year
13
13
  const MAX_CONVO = 20
14
14
  const page_loaded = sb.Date.now()
15
15
 
16
- // available localstorage key mask, user, session, hasManuallyClosed, isopen, close_preview_at, lastview, bot_run_logs, plugin_run_logs
16
+ // available localstorage key mask, user, hasManuallyClosed, isopen, close_preview_at, lastview, bot_run_logs, plugin_run_logs
17
17
  export default class Store {
18
18
  constructor(ApiURL, FileURL, RealtimeURL, inmem, fakeapi, agenttoken) {
19
19
  this.agent_token = agenttoken
@@ -98,7 +98,8 @@ export default class Store {
98
98
  }
99
99
 
100
100
  isInsync(key) {
101
- return sb.Date.now() - (this.g_sync[key] || 0) < 300000
101
+ // refetch after 10 mins
102
+ return sb.Date.now() - (this.g_sync[key] || 0) < 600000
102
103
  }
103
104
 
104
105
  async fetchShippingAddresses() {
@@ -114,6 +115,7 @@ export default class Store {
114
115
  updateOrder(order) {
115
116
  return this.api.updateOrder(order)
116
117
  }
118
+
117
119
  createShippingAddress(addr) {
118
120
  return this.api.createShippingAddress(addr)
119
121
  }
@@ -218,7 +220,6 @@ export default class Store {
218
220
 
219
221
  suggest_addresses = (keyword) => this.api.suggest_address(keyword)
220
222
 
221
- matchSession = () => this.kv.match('session') || {}
222
223
  matchAccount = () => this.cache.match('account')
223
224
  matchPaymentMethods = () => this.cache.match('payment_methods')
224
225
 
@@ -303,6 +304,8 @@ export default class Store {
303
304
  return {error}
304
305
  }
305
306
 
307
+ matchLocation = () => this.cache.match('location') || {}
308
+
306
309
  matchBot = () => this.cache.match('bot') || {}
307
310
 
308
311
  readyGate = new sb.Gate()
@@ -530,26 +533,6 @@ export default class Store {
530
533
  // user && session
531
534
  if (setting.user) {
532
535
  setting.user.account_id = setting.account.id
533
- let oldsession = this.matchSession()
534
- let session = setting.user.session
535
- if (session) {
536
- if (session.id === oldsession.id) {
537
- // refresh session, but keep old local fields
538
- session._urls = oldsession._urls
539
- } else {
540
- // session changed, clear all old data
541
- }
542
- } else {
543
- // dont change session
544
- session = oldsession
545
- }
546
-
547
- session._urls = session._urls || []
548
- session._urls.push(location.href)
549
- while (session._urls.length > 1000) session._urls.shift()
550
-
551
- this.kv.put('session', session)
552
-
553
536
  delete setting.user.session
554
537
  this._setUser(setting.user)
555
538
  }
@@ -561,6 +544,10 @@ export default class Store {
561
544
  delete setting.account
562
545
  }
563
546
 
547
+ // location
548
+ let location = sb.get(setting, 'location', [])
549
+ this.cache.put('location', location)
550
+
564
551
  // bot
565
552
  let bots = sb.get(setting, 'bots', [])
566
553
  let botM = {}
@@ -601,7 +588,7 @@ export default class Store {
601
588
  // send the content view, the first presence and record domain
602
589
  async track() {
603
590
  let user = this.kv.match('user') || {}
604
- await this.api.sendContentView(
591
+ let out = await this.api.sendContentView(
605
592
  this.device,
606
593
  location.href,
607
594
  document.title,
@@ -609,9 +596,15 @@ export default class Store {
609
596
  this._currentViewingProduct.source_id,
610
597
  this._currentViewingProduct.sku,
611
598
  )
599
+
600
+ let traffic_source = sb.get(out, 'body.by.device.source', '')
601
+ if (traffic_source) this.kv.put('traffic_source', traffic_source)
602
+
612
603
  this.sendPresence()
613
604
  }
614
605
 
606
+ matchTrafficSource = () => this.kv.match('traffic_source')
607
+
615
608
  async onWs(ev) {
616
609
  if (!ev || !ev.type) return
617
610
  ev.created = sb.getMs(ev.created)
@@ -925,17 +918,15 @@ export default class Store {
925
918
  }
926
919
 
927
920
  logBotRun(botid) {
928
- let session = this.matchSession()
929
921
  let log = this.kv.match('bot_run_logs') || {}
930
- log[botid] = {bot_id: botid, created: this.now(), session_id: session.id}
922
+ log[botid] = {bot_id: botid, created: this.now()}
931
923
  this.kv.put('bot_run_logs', log)
932
924
  }
933
925
 
934
926
  sendImpression(id) {
935
927
  let user = this.kv.match('user') || {}
936
928
  let log = this.kv.match('plugin_run_logs') || {}
937
- let session = this.matchSession()
938
- log[id] = {web_plugin_id: id, created: this.now(), session_id: session.id}
929
+ log[id] = {web_plugin_id: id, created: this.now()}
939
930
  this.kv.put('plugin_run_logs', log)
940
931
  return this.api.sendImpression({
941
932
  account_id: user.account_id,
@@ -944,7 +935,6 @@ export default class Store {
944
935
  user_id: user.id,
945
936
  url: window.location.href,
946
937
  device: this.device,
947
- session_id: session.id,
948
938
  })
949
939
  }
950
940
 
@@ -965,7 +955,6 @@ export default class Store {
965
955
  device: this.device,
966
956
  submission,
967
957
  impression_token: impressionToken,
968
- session_id: this.matchSession().id,
969
958
  })
970
959
  }
971
960
 
@@ -1007,7 +996,7 @@ export default class Store {
1007
996
  let startms = sb.Date.now()
1008
997
 
1009
998
  // store not init
1010
- if (!sb.get(this.kv.match('user'), 'id')) return setTimeout(() => this.loopTime(), 120000)
999
+ if (!sb.get(this.kv.match('user'), 'id')) return setTimeout(() => this.loopTime(), 240000)
1011
1000
 
1012
1001
  let {body: t, error} = await this.api.time()
1013
1002
  if (error) return setTimeout(() => this.loopTime(), 30000)
@@ -1015,7 +1004,7 @@ export default class Store {
1015
1004
  var serverMs = new sb.Date(t).getTime() + latences
1016
1005
  var localMs = sb.Date.now()
1017
1006
  this.timeDiff = Math.floor(serverMs - localMs)
1018
- setTimeout(() => this.loopTime(), 120000)
1007
+ setTimeout(() => this.loopTime(), 240000)
1019
1008
  }
1020
1009
 
1021
1010
  replaceFileUrl(src) {
@@ -1161,16 +1150,15 @@ function sendToFBPixel(category, action, label) {
1161
1150
  }
1162
1151
 
1163
1152
  function sendToGA(category, action, label) {
1164
- console.log('SENT.', category, action, label)
1153
+ // console.log('SENT.', category, action, label)
1154
+ if (window.gtag) window.gtag('event', category, {Action: action, Label: label})
1165
1155
  if (window.ga && window.ga.getAll) {
1156
+ // only send gtag when ga is not available
1166
1157
  const allTrackers = window.ga.getAll() || []
1167
1158
  allTrackers.forEach(function (tracker) {
1168
1159
  const name = tracker.get('name')
1169
1160
  window.ga(name + '.send', 'event', category, action, label)
1170
1161
  })
1171
- } else {
1172
- // only send gtag when ga is not available
1173
- if (window.gtag) window.gtag('event', category, {Action: action, Label: label})
1174
1162
  }
1175
1163
  }
1176
1164
 
@@ -247,13 +247,13 @@ export function throttle(func, wait, options) {
247
247
  var timeout = null
248
248
  var previous = 0
249
249
  if (!options) options = {}
250
- var later = function() {
250
+ var later = function () {
251
251
  previous = options.leading === false ? 0 : new Date().getTime()
252
252
  timeout = null
253
253
  result = func.apply(context, args)
254
254
  if (!timeout) context = args = null
255
255
  }
256
- return function() {
256
+ return function () {
257
257
  var now = new Date().getTime()
258
258
  if (!previous && options.leading === false) previous = now
259
259
  var remaining = wait - (now - previous)
@@ -331,7 +331,8 @@ export function isNumber(num) {
331
331
  }
332
332
 
333
333
  export function isEmail(email) {
334
- const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
334
+ const re =
335
+ /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
335
336
  return re.test(String(email).toLowerCase())
336
337
  }
337
338
 
@@ -650,7 +651,7 @@ function browserName() {
650
651
  // Safari 3.0+ "[object HTMLElementConstructor]"
651
652
  var isSafari =
652
653
  /constructor/i.test(window.HTMLElement) ||
653
- (function(p) {
654
+ (function (p) {
654
655
  return p.toString() === '[object SafariRemoteNotification]'
655
656
  })(!window['safari'] || (typeof safari !== 'undefined' && window['safari'].pushNotification))
656
657
 
@@ -697,15 +698,10 @@ function osName() {
697
698
  // frequencty
698
699
  function check_frequently(freq, lastrun, store) {
699
700
  if (!lastrun) return true
700
- // only for popup?
701
- //var run = store.matchLastPluginRun(plugin.id)
702
- //if (!run) return true
703
-
704
701
  if (op.get(freq, 'once_per_user')) return false
705
702
 
706
- var session = store.matchSession() || {}
707
703
  if (op.get(freq, 'once_per_session')) {
708
- if (lastrun.session_id === session.id) return false
704
+ if (sameDay(lastrun.created, Date.now())) return false
709
705
  }
710
706
 
711
707
  if (op.get(freq, 'interval_sec')) {
@@ -718,7 +714,7 @@ function check_frequently(freq, lastrun, store) {
718
714
 
719
715
  export function checkRunConditions(freq, conds, lastrun, store) {
720
716
  var acc = store.matchAccount() || {}
721
- var session = store.matchSession() || {}
717
+ var location = store.matchLocation() || {}
722
718
 
723
719
  // check frequently first
724
720
  if (!check_frequently(freq, lastrun, store)) return false
@@ -754,13 +750,13 @@ export function checkRunConditions(freq, conds, lastrun, store) {
754
750
  if (size(cond.exclude_locations) > 0) {
755
751
  let found = find(cond.exclude_locations, (loc) => {
756
752
  if (loc.city_name && loc.country_code) {
757
- if (loc.city_name === session.city_name && loc.country_code === session.country_code) return true
753
+ if (loc.city_name === location.city_name && loc.country_code === location.country_code) return true
758
754
  }
759
755
  if (loc.city_name && !loc.country_code) {
760
- if (loc.city_name === session.city_name) return true
756
+ if (loc.city_name === location.city_name) return true
761
757
  }
762
758
  if (!loc.city_name && loc.country_code) {
763
- if (loc.country_code === session.country_code) return true
759
+ if (loc.country_code === location.country_code) return true
764
760
  }
765
761
  })
766
762
  if (found) return false
@@ -769,13 +765,13 @@ export function checkRunConditions(freq, conds, lastrun, store) {
769
765
  if (size(cond.locations) > 0) {
770
766
  let found = find(cond.locations, (loc) => {
771
767
  if (loc.city_name && loc.country_code) {
772
- if (loc.city_name === session.city_name && loc.country_code === session.country_code) return true
768
+ if (loc.city_name === location.city_name && loc.country_code === location.country_code) return true
773
769
  }
774
770
  if (loc.city_name && !loc.country_code) {
775
- if (loc.city_name === session.city_name) return true
771
+ if (loc.city_name === location.city_name) return true
776
772
  }
777
773
  if (!loc.city_name && loc.country_code) {
778
- if (loc.country_code === session.country_code) return true
774
+ if (loc.country_code === location.country_code) return true
779
775
  }
780
776
  })
781
777
  if (!found) return false
@@ -828,7 +824,8 @@ export function checkRunConditions(freq, conds, lastrun, store) {
828
824
  break
829
825
  case 'source':
830
826
  if (size(cond.sources) > 0) {
831
- if (!find(cond.sources, (src) => norm(src) === norm(session.source))) return false
827
+ let source = store.matchTrafficSource()
828
+ if (!find(cond.sources, (src) => norm(src) === norm(source))) return false
832
829
  }
833
830
  break
834
831
  case 'user_attribute':
@@ -1077,7 +1074,7 @@ export var sleep = (ms) => new Promise((res) => setTimeout(res, ms))
1077
1074
  export function formatCurrency(val) {
1078
1075
  if (!val) return '0 đ'
1079
1076
  val = Math.round(val)
1080
- return val.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')+ ' đ'
1077
+ return val.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') + ' đ'
1081
1078
  }
1082
1079
 
1083
1080
  function replaceFileUrl(src) {