@subiz/widget-v4 4.1.61 → 4.1.63

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 (49) hide show
  1. package/README.md +10 -0
  2. package/app.js +2 -6
  3. package/assets/less/widget.less +16 -7
  4. package/dist/{213.js → 132.js} +121 -121
  5. package/dist/18dd22fb422.132.js +1 -0
  6. package/dist/18dd22fb422.27.js +1 -0
  7. package/dist/18dd22fb422.278.js +1 -0
  8. package/dist/18dd22fb422.459.js +1 -0
  9. package/dist/{18d5e97bf55.605.js → 18dd22fb422.490.js} +1 -1
  10. package/dist/18dd22fb422.497.js +1 -0
  11. package/dist/18dd22fb422.74.js +1 -0
  12. package/dist/18dd22fb422.997.js +1 -0
  13. package/dist/18dd22fb422.app.js +1 -0
  14. package/dist/{18d5e97bf55.index.html → 18dd22fb422.index.html} +1 -1
  15. package/dist/{18d5e97bf55.library.html → 18dd22fb422.library.html} +1 -1
  16. package/dist/18dd22fb422.library.js +1 -0
  17. package/dist/{18d5e97bf55.preview.html → 18dd22fb422.preview.html} +1 -1
  18. package/dist/18dd22fb422.preview.js +1 -0
  19. package/dist/18dd22fb422.screenshoot.js +1 -0
  20. package/dist/18dd22fb422.webview.js +1 -0
  21. package/dist/{782.js → 27.js} +6 -6
  22. package/dist/{178.js → 278.js} +54 -54
  23. package/dist/{362.js → 459.js} +6 -6
  24. package/dist/{605.js → 490.js} +57 -57
  25. package/dist/{841.js → 497.js} +688 -677
  26. package/dist/{335.js → 74.js} +30 -30
  27. package/dist/{678.js → 997.js} +6 -6
  28. package/dist/HASH +1 -1
  29. package/dist/malicious-app.js +4 -8
  30. package/dist/screenshoot.html +1 -1
  31. package/dist/screenshoot.js +291 -291
  32. package/malicious-app.js +4 -8
  33. package/package.json +6 -6
  34. package/src/chatbox/Widget.js +56 -32
  35. package/src/store/api.js +17 -0
  36. package/src/store/api_fake.js +3 -0
  37. package/src/store/store.js +16 -50
  38. package/dist/18d5e97bf55.178.js +0 -1
  39. package/dist/18d5e97bf55.213.js +0 -1
  40. package/dist/18d5e97bf55.335.js +0 -1
  41. package/dist/18d5e97bf55.362.js +0 -1
  42. package/dist/18d5e97bf55.678.js +0 -1
  43. package/dist/18d5e97bf55.782.js +0 -1
  44. package/dist/18d5e97bf55.841.js +0 -1
  45. package/dist/18d5e97bf55.app.js +0 -1
  46. package/dist/18d5e97bf55.library.js +0 -1
  47. package/dist/18d5e97bf55.preview.js +0 -1
  48. package/dist/18d5e97bf55.screenshoot.js +0 -1
  49. package/dist/18d5e97bf55.webview.js +0 -1
package/malicious-app.js CHANGED
@@ -8,12 +8,8 @@ tag.defer = true
8
8
  tag.src = 'https://public-gcs.subiz-cdn.com/widget-v4/public/' + hash + '.app.js'
9
9
  document.body.appendChild(tag)
10
10
 
11
- if (document.readyState === "interactive" || document.readyState === "complete") document.body.appendChild(tag)
12
- else document.addEventListener("DOMContentLoaded", function(event) {
11
+ if (document.readyState === 'interactive' || document.readyState === 'complete') document.body.appendChild(tag)
12
+ else
13
+ document.addEventListener('DOMContentLoaded', function (event) {
13
14
  document.body.appendChild(tag)
14
- }) //
15
-
16
- // record which domain still use old code
17
- var xhttp = new XMLHttpRequest()
18
- xhttp.open('GET', 'https://api.sbz.vn/4.0/old', true)
19
- xhttp.send()
15
+ }) //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/widget-v4",
3
- "version": "4.1.61",
3
+ "version": "4.1.63",
4
4
  "main": "./compiled_src/lib.js",
5
5
  "scripts": {
6
6
  "dev": "npx webpack serve --config webpack.dev.js",
@@ -14,12 +14,12 @@
14
14
  "@subiz/storage": "0.0.8",
15
15
  "@subiz/wsclient": "^4.0.21",
16
16
  "cookie_js": "1.4.2",
17
- "core-js": "^3.35.1",
17
+ "core-js": "^3.36.0",
18
18
  "css-loader": "5.2.7",
19
19
  "file-loader": "^6.2.0",
20
20
  "less": "^4.2.0",
21
21
  "less-loader": "^12.2.0",
22
- "preact": "^10.19.3"
22
+ "preact": "10.19.3"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@babel/cli": "^7.23.9",
@@ -30,10 +30,10 @@
30
30
  "babel-loader": "^9.1.3",
31
31
  "babel-plugin-syntax-jsx": "^6.18.0",
32
32
  "html-webpack-plugin": "^5.6.0",
33
- "puppeteer": "^22.0.0",
34
- "webpack": "^5.90.1",
33
+ "puppeteer": "^22.2.0",
34
+ "webpack": "^5.90.3",
35
35
  "webpack-bundle-analyzer": "^4.10.1",
36
36
  "webpack-cli": "^5.1.4",
37
- "webpack-dev-server": "^4.15.1"
37
+ "webpack-dev-server": "^5.0.2"
38
38
  }
39
39
  }
@@ -43,12 +43,14 @@ export default class Widget extends Com {
43
43
  msgInput = createRef()
44
44
  componentDidMount() {
45
45
  if (!this.props.store.isMobile()) this.focusInput()
46
+ this.updateFormDataFields()
46
47
  }
47
48
 
48
49
  componentDidUpdate(prevProp) {
49
50
  if (prevProp.isShow !== this.props.isShow) {
50
51
  if (this.props.isShow && !this.props.store.isMobile()) this.focusInput()
51
52
  if (this.props.isShow && this.props.store.isMobile()) this.blur()
53
+ this.updateFormDataFields()
52
54
  }
53
55
 
54
56
  if (prevProp.cid !== this.props.cid) {
@@ -62,9 +64,9 @@ export default class Widget extends Com {
62
64
  this.events && this.events.focus()
63
65
  if (!this.props.store.isMobile()) this.focusInput()
64
66
  }, 100)
67
+ this.updateFormDataFields()
65
68
  }
66
-
67
- this.updateFormDataFields()
69
+ // this.updateFormDataFields()
68
70
  }
69
71
 
70
72
  shouldShowForm() {
@@ -85,6 +87,7 @@ export default class Widget extends Com {
85
87
 
86
88
  render() {
87
89
  let showform = this.shouldShowForm()
90
+ let formName = ''
88
91
 
89
92
  let form
90
93
  // choose form to display
@@ -97,11 +100,13 @@ export default class Widget extends Com {
97
100
  if (this.isOffline(acc, accountSetting) && offlineEnabled) {
98
101
  form = accountSetting.offline_form
99
102
  submitLabel = this.props.t('offline_form_btn')
103
+ formName = 'offline'
100
104
  }
101
105
 
102
106
  if (this.props.view === 'offline_form') {
103
107
  showform = true
104
108
  form = accountSetting.offline_form
109
+ formName = 'offline'
105
110
  submitLabel = this.props.t('offline_form_btn')
106
111
  }
107
112
 
@@ -109,11 +114,12 @@ export default class Widget extends Com {
109
114
  showform = true
110
115
  form = accountSetting.prechat_form
111
116
  submitLabel = this.props.t('prechat_form_btn')
117
+ formName = 'prechat'
112
118
  }
113
119
 
114
120
  let $body = null
115
121
  if (this.props.view === 'list') $body = this.renderConvoList()
116
- else if (showform) $body = this.renderForm(form, submitLabel)
122
+ else if (showform) $body = this.renderForm(form, submitLabel, formName)
117
123
  else $body = this.renderChat()
118
124
 
119
125
  let position = sb.get(accountSetting, 'desktop_button.position') || 'right'
@@ -138,7 +144,8 @@ export default class Widget extends Com {
138
144
  )
139
145
  }
140
146
 
141
- async submitPrechatForm(form) {
147
+ async submitPrechatForm(form, fornName) {
148
+ if (this.state.submiting) return
142
149
  // check error first
143
150
  var hasError = false
144
151
  sb.map(this.state.formData, (field, key) => {
@@ -183,8 +190,22 @@ export default class Widget extends Com {
183
190
  let firstmsg = sb.get(data, 'question.value')
184
191
  let groupid = sb.get(data, 'group.value', '')
185
192
 
193
+ // creating convo
194
+ this._creating = (this._creating || 0) + 1
195
+ let _creating = this._creating
196
+ this.setState({creating: true})
197
+ let out = await this.props.store.submitForm(
198
+ 'chatbox_' + fornName,
199
+ sb.map(data, (field, key) => {
200
+ return {key: key, type: field.type, value: field.value + ''}
201
+ }),
202
+ user,
203
+ )
204
+
205
+ if (_creating != this._creating) return // outdated
206
+ return
186
207
  if (this.props.cid) {
187
- this.props.store.setUser(user)
208
+ // this.props.store.setUser(user)
188
209
  this.setState({clickedJoin: false})
189
210
  // form will auto disappear after rerender
190
211
  await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {
@@ -195,36 +216,39 @@ export default class Widget extends Com {
195
216
  attachments: this.state.quickReplyMessage.attachments,
196
217
  },
197
218
  })
198
-
219
+ if (_creating != this._creating) return // outdated
199
220
  // reset quickReplyMessage
200
- this.setState({quickReplyMessage: {}})
221
+ this.setState({creating: false, quickReplyMessage: {}})
201
222
 
202
223
  // end_conversation_after_submit only for offline form or prechat form
203
224
  if (form.end_conversation_after_submit) await this.props.store.endConvo(this.props.cid)
225
+ if (_creating != this._creating) return // outdated
204
226
  return
205
227
  }
206
228
 
207
- // creating convo
208
- this.setState({creating: true})
229
+ return
230
+
209
231
  let message = {text: firstmsg, format: 'plaintext'}
210
232
  let req = {group_id: groupid, message: firstmsg, locale: this.props.t.locale(), initial_by: user.id}
211
233
 
212
234
  this.setState({creatingError: null})
213
- await this.props.store.setUser(user)
235
+ // await this.props.store.setUser(user)
214
236
  const {error, convo} = await this.props.store.startConvo(req)
237
+ if (_creating != this._creating) return // outdated
215
238
  if (error) {
216
239
  this.setState({creating: false, creatingError: error})
217
240
  return
218
241
  }
219
242
  let newconvoid = convo.id
220
243
  this.userSent[newconvoid] = true
221
- this.props.onGo({view: 'chat', cid: newconvoid})
222
- this.props.store.sendConvoEvent(newconvoid, 'message_sent', {message})
244
+ await this.props.store.sendConvoEvent(newconvoid, 'message_sent', {message})
245
+ if (_creating != this._creating) return // outdated
223
246
  this.setState({
224
247
  creating: false,
225
248
  clickedJoin: false,
226
249
  quickReplyMessage: {},
227
250
  })
251
+ this.props.onGo({view: 'chat', cid: newconvoid})
228
252
  if (!this.props.store.isMobile()) this.focusInput()
229
253
  }
230
254
 
@@ -240,7 +264,6 @@ export default class Widget extends Com {
240
264
  }
241
265
 
242
266
  this.setState({formData})
243
-
244
267
  if (!this.props.store.isMobile()) this.focusInput()
245
268
  }
246
269
 
@@ -401,7 +424,6 @@ export default class Widget extends Com {
401
424
 
402
425
  renderFields() {
403
426
  if (sb.size(this.state.formData) === 0) return null
404
-
405
427
  let $fields = sb.map(this.state.formData, (field, key) => {
406
428
  // not display question when click bot quick reply
407
429
  if (this.state.quickReplyMessage.text && key === 'question') return null
@@ -437,6 +459,7 @@ export default class Widget extends Com {
437
459
  }}
438
460
  value={field.value || ''}
439
461
  onInput={(e) => this.onInputChange(key, e.target.value)}
462
+ onChange={(e) => this.onInputChange(key, e.target.value)}
440
463
  row='4'
441
464
  class='form-control'
442
465
  ></textarea>
@@ -446,6 +469,7 @@ export default class Widget extends Com {
446
469
  <input
447
470
  value={field.value || ''}
448
471
  onInput={(e) => this.onInputChange(key, e.target.value)}
472
+ onChange={(e) => this.onInputChange(key, e.target.value)}
449
473
  ref={(ref) => {
450
474
  this['form_' + encode(key)] = ref
451
475
  }}
@@ -537,9 +561,8 @@ export default class Widget extends Com {
537
561
  label = field.label || this.props.t('your_question')
538
562
  }
539
563
  if (field.label) label = field.label
540
-
541
564
  return (
542
- <div>
565
+ <div key={'form_' + encode(key)}>
543
566
  <div class='label'>
544
567
  {label}
545
568
  {field.is_required ? <span class='ml-1 red'>*</span> : ''}
@@ -552,15 +575,7 @@ export default class Widget extends Com {
552
575
  return <div class='pt-2'>{$fields}</div>
553
576
  }
554
577
 
555
- renderForm(form, submitLabel) {
556
- let $loading = null
557
- if (this.state.creating)
558
- $loading = (
559
- <span class='ml-2'>
560
- <Spinner size='16' mode='white' />
561
- </span>
562
- )
563
-
578
+ renderForm(form, submitLabel, formName) {
564
579
  let title = this.props.t.i18n(sb.get(form, `i18n_title`, {}))
565
580
  if (!title) title = sb.get(form, 'title', this.props.t('capture_lead_title'))
566
581
  // replace ↵ character
@@ -581,8 +596,12 @@ export default class Widget extends Com {
581
596
  </div>
582
597
 
583
598
  <div class='message-input message-input--preform'>
584
- <button class='btn--start-convo' onClick={(_) => this.submitPrechatForm(form)}>
585
- {submitLabel} {$loading}
599
+ <button
600
+ class='btn--start-convo'
601
+ onClick={(_) => this.submitPrechatForm(form, formName)}
602
+ disabled={this.state.creating}
603
+ >
604
+ {submitLabel}
586
605
  </button>
587
606
  </div>
588
607
  </div>
@@ -710,23 +729,28 @@ export default class Widget extends Com {
710
729
 
711
730
  let text = message.text
712
731
  if (!this.props.cid) {
713
- this.creating = true
732
+ this._creating = (this._creating || 0) + 1
733
+ let _creating = this._creating
734
+ this.setState({creating: true})
714
735
  const {convo, error} = await this.props.store.startConvo({
715
736
  locale: this.props.t.locale(),
716
737
  message: text,
717
738
  initial_by: this.props.store.matchUser().id,
718
739
  })
740
+ if (_creating != this._creating) return // outdated
719
741
  if (error) {
720
742
  // show error and try again
721
743
  }
722
- this.creating = false
723
- this.props.store.sendConvoEvent(convo.id, 'message_sent', {message})
744
+ await this.props.store.sendConvoEvent(convo.id, 'message_sent', {message})
745
+ if (_creating != this._creating) return // outdated
746
+ this.setState({creating: false})
724
747
 
725
748
  this.props.onGo({view: 'chat', cid: convo.id})
726
-
727
749
  return
728
750
  }
729
- this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
751
+ await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
752
+ if (_creating != this._creating) return // outdated
753
+ this.setState({creating: false})
730
754
  }
731
755
 
732
756
  createPostback(postback) {
package/src/store/api.js CHANGED
@@ -220,6 +220,23 @@ export default class {
220
220
  getLocaleContent = (locale) => this.apireq.get(`/accounts/${this.accid}/locales/${locale}`)
221
221
  sendEvent = (data) =>
222
222
  this.apireq.addQuery('shorten', true).post(`/accounts/${this.accid}/users/${this.uid}/events`, data)
223
+
224
+ submitForm = (form_id, page_url, device, data, user) =>
225
+ this.apireq.post(`/accounts/${this.accid}/users/${this.uid}/events`, {
226
+ by: {id: this.uid, device: device},
227
+ type: 'form_submitted',
228
+ data: {
229
+ user: user,
230
+ form_submitted: {
231
+ user_id: this.uid,
232
+ form_id: form_id,
233
+ page_url: page_url,
234
+ submitted_at: sb.Date.now(),
235
+ values: data,
236
+ },
237
+ },
238
+ })
239
+
223
240
  sendTyping = (cid) => this.apireq.post(`/accounts/${this.accid}/conversations/${cid}/typing`)
224
241
 
225
242
  sendLostFocus = (device, productid, source_id, sku) =>
@@ -63,6 +63,9 @@ export default class {
63
63
  Promise.resolve({body: makeFakeConvo(this.accid, 'csqwudlkftltnbebvq', this.uid, this.agentid), code: 200})
64
64
  getLocaleContent = (locale) => this.apireq.get(`/accounts/${this.accid}/locales/${locale}`)
65
65
  sendEvent = (data) => OK200
66
+
67
+ submitForm = (form_id, page_url, device, data, user) => OK200
68
+
66
69
  sendTyping = (cid) => OK200
67
70
 
68
71
  sendPresence = (data) => OK200
@@ -372,16 +372,16 @@ export default class Store {
372
372
  return
373
373
  }
374
374
 
375
- if (this._track_page_view) {
376
- this.api.sendContentView(
377
- this.device,
378
- location.href,
379
- document.title,
380
- this._currentViewingProduct.id,
381
- this._currentViewingProduct.source_id,
382
- this._currentViewingProduct.sku,
383
- )
384
- }
375
+ if (this._track_page_view) {
376
+ this.api.sendContentView(
377
+ this.device,
378
+ location.href,
379
+ document.title,
380
+ this._currentViewingProduct.id,
381
+ this._currentViewingProduct.source_id,
382
+ this._currentViewingProduct.sku,
383
+ )
384
+ }
385
385
  },
386
386
  1000, // dont send presence update too tight
387
387
  {leading: false}, // dont send right after load. should send after content_view
@@ -572,6 +572,12 @@ export default class Store {
572
572
  return this.reconnectGate.open()
573
573
  }
574
574
 
575
+ async submitForm(formid, data, user) {
576
+ await this.readyGate.entry()
577
+ if (user) await this.setUser(user)
578
+ return this.api.submitForm(formid, document.URL, this.device, data, user)
579
+ }
580
+
575
581
  // set user info, keeping old user id and account id
576
582
  async setUser(user) {
577
583
  if (!user) return
@@ -814,7 +820,6 @@ export default class Store {
814
820
  }
815
821
 
816
822
  convo.last_message_sent = ev
817
- // this.handleFormSubmit(convoKey, ev)
818
823
  }
819
824
 
820
825
  // dont store pong and typing
@@ -825,45 +830,6 @@ export default class Store {
825
830
  this.pubsub.publish('account')
826
831
  }
827
832
 
828
- handleFormSubmit(convoKey, ev) {
829
- // find form submit
830
- if (ev.type !== 'message_sent') return
831
- // has form submit
832
- let formSubmits = []
833
- let attachments = sb.get(ev, 'data.message.attachments') || []
834
- sb.each(attachments, (att) => {
835
- if (!att) return
836
- if (att.type !== 'form_submit') return
837
- formSubmits.push(att.form_submit)
838
- })
839
-
840
- sb.each(formSubmits, (submit) => {
841
- let formev = sb.get(this.convoEventM, convoKey + '.' + submit.form_message_id)
842
- if (!formev) return
843
-
844
- // find form attachment
845
- let forms = sb.filter(sb.get(formev, 'data.message.attachments'), (att) => {
846
- if (!att) return false
847
- if (att.type !== 'form' && att.type !== 'ask_info_form') return false
848
- return true
849
- })
850
-
851
- sb.each(forms, (form) => {
852
- form = form.form
853
- sb.each(form.fields, (formfield) => {
854
- sb.each(submit.fields, (submitfield) => {
855
- if (formfield.name !== submitfield.name) return
856
- if (formfield.default_answer) return
857
-
858
- formfield.default_answer = submitfield.value
859
- })
860
- })
861
- })
862
-
863
- if (sb.size(forms) > 0) this.pubsub.publish('state.convoEventM', this.convoEventM, convoKey)
864
- })
865
- }
866
-
867
833
  typing(cid) {
868
834
  if (!cid) return
869
835
  this._typing(cid)