@subiz/widget-v4 4.1.190 → 4.1.195
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.
- package/assets/less/chatbox.less +0 -1
- package/assets/less/message.less +71 -4
- package/compiled_src/chatbox/Event.js +38 -8
- package/compiled_src/chatbox/Events.js +20 -0
- package/compiled_src/chatbox/FileAttachments.js +36 -4
- package/compiled_src/chatbox/ImageAttachments.js +31 -4
- package/compiled_src/chatbox/QuoteMessage.js +99 -0
- package/compiled_src/chatbox/Rating.js +4 -0
- package/compiled_src/chatbox/TextMessage.js +49 -4
- package/compiled_src/chatbox/Widget.js +43 -1
- package/compiled_src/store/api.js +2 -0
- package/compiled_src/store/store.js +44 -2
- package/compiled_src/util/common.js +13 -1
- package/dist/127.js +273 -0
- package/dist/132.js +2802 -0
- package/dist/185.js +1827 -0
- package/dist/19b74edd3c9.127.js +1 -0
- package/dist/19b74edd3c9.132.js +1 -0
- package/dist/19b74edd3c9.185.js +1 -0
- package/dist/19b74edd3c9.27.js +1 -0
- package/dist/19b74edd3c9.278.js +1 -0
- package/dist/19b74edd3c9.339.js +1 -0
- package/dist/19b74edd3c9.459.js +1 -0
- package/dist/19b74edd3c9.490.js +1 -0
- package/dist/19b74edd3c9.74.js +1 -0
- package/dist/19b74edd3c9.997.js +1 -0
- package/dist/19b74edd3c9.app.js +1 -0
- package/dist/19b74edd3c9.chat.html +1 -0
- package/dist/19b74edd3c9.chat.js +1 -0
- package/dist/19b74edd3c9.form.html +1 -0
- package/dist/19b74edd3c9.form.js +1 -0
- package/dist/19b74edd3c9.index.html +72 -0
- package/dist/19b74edd3c9.library.html +72 -0
- package/dist/19b74edd3c9.library.js +1 -0
- package/dist/19b74edd3c9.preview.html +759 -0
- package/dist/19b74edd3c9.preview.js +1 -0
- package/dist/19b74edd3c9.webview.js +1 -0
- package/dist/27.js +35 -0
- package/dist/459.js +35 -0
- package/dist/490.js +305 -0
- package/dist/74.js +372 -0
- package/dist/997.js +35 -0
- package/dist/HASH +1 -0
- package/dist/assets/img/Facebook.64607ec.png +0 -0
- package/dist/assets/img/Zalo.6845707.png +0 -0
- package/dist/assets/img/award1a.1a58e10.png +0 -0
- package/dist/assets/img/award3a.3b74423.png +0 -0
- package/dist/assets/img/award4a.ed6ccd4.png +0 -0
- package/dist/assets/img/award5.39eb7ae.png +0 -0
- package/dist/assets/img/bubble_default.7d5e4ab.svg +20 -0
- package/dist/assets/img/caret.998eb8f.svg +1 -0
- package/dist/assets/img/convos_empty.2353007.svg +72 -0
- package/dist/assets/img/default.06e6ee0.jpg +0 -0
- package/dist/assets/img/default_avatar.5b74dc1.png +0 -0
- package/dist/assets/img/done_gray.d7e8203.svg +4 -0
- package/dist/assets/img/done_green.b817fd4.svg +4 -0
- package/dist/assets/img/emoji/messenger/sub_23.529_58.824.d5faf14.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_23.529_60.784.1420241.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_0.000.1e6b2c0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_45.098.3dfbc08.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_25.490_5.882.4b49e94.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_72.549.7114f58.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_84.314.231e2b7.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_27.451_96.078.ddbb008.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_29.412_5.882.61f3359.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_100.000.6df72bc.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_45.098.3d7a7ad.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_47.059.0f4d6e2.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_54.902.65724c1.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_64.706.9da3cba.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_72.549.edca5cf.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_78.431.f910f2a.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_58.824_88.235.def4e71.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_11.765.49c03d0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_27.451.46b54e5.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_29.412.e36d284.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_3.922.bb191b0.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_35.294.af7b927.png +0 -0
- package/dist/assets/img/emoji/messenger/sub_60.784_7.843.98f2a99.png +0 -0
- package/dist/assets/img/empty.29bed2d.svg +23 -0
- package/dist/assets/img/empty_1.0b98af0.svg +11 -0
- package/dist/assets/img/examplte_logo.f86535f.svg +1 -0
- package/dist/assets/img/external-link.90577cc.svg +1 -0
- package/dist/assets/img/fb_inverse_circle.36c2cfc.png +0 -0
- package/dist/assets/img/ghn.070f8e3.svg +17 -0
- package/dist/assets/img/ghtk.326eac1.svg +18 -0
- package/dist/assets/img/image_default.be0698b.png +0 -0
- package/dist/assets/img/info.ebce7ea.svg +1 -0
- package/dist/assets/img/loader.37000a7.svg +1 -0
- package/dist/assets/img/loading_static.a27f0ac.svg +10 -0
- package/dist/assets/img/main-service1.d536cc2.png +0 -0
- package/dist/assets/img/main-service2.9b99549.png +0 -0
- package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
- package/dist/assets/img/package.8d37d0f.svg +5 -0
- package/dist/assets/img/package_fade.763c001.svg +1 -0
- package/dist/assets/img/rating--average.1ea492c.svg +12 -0
- package/dist/assets/img/rating--great.e3d712e.svg +16 -0
- package/dist/assets/img/rating--poor.2938a25.svg +12 -0
- package/dist/assets/img/search.f9705ff.svg +1 -0
- package/dist/assets/img/send.6db52a9.svg +3 -0
- package/dist/assets/img/shop.f7dc7d8.svg +1 -0
- package/dist/assets/img/shop_faded.df7845a.svg +1 -0
- package/dist/assets/img/stars_v2.79cf728.png +0 -0
- package/dist/assets/img/subiz-mono.8fbc067.svg +3 -0
- package/dist/assets/img/x.26fdfa3.svg +5 -0
- package/dist/malicious-app.js +17 -0
- package/dist/screenshoot.html +7 -0
- package/dist/screenshoot.js +13015 -0
- package/package.json +8 -8
- package/src/chatbox/Event.js +49 -9
- package/src/chatbox/Events.js +21 -1
- package/src/chatbox/FileAttachments.js +31 -4
- package/src/chatbox/ImageAttachments.js +26 -3
- package/src/chatbox/QuoteMessage.js +94 -0
- package/src/chatbox/Rating.js +5 -0
- package/src/chatbox/TextMessage.js +50 -2
- package/src/chatbox/Widget.js +52 -0
- package/src/store/api.js +3 -0
- package/src/store/store.js +50 -1
- package/src/util/common.js +19 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subiz/widget-v4",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.195",
|
|
4
4
|
"main": "./compiled_src/lib.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npx webpack serve --config webpack.dev.js",
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
"lib": "rm -rf compiled_src && npx babel --out-dir=compiled_src src"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@subiz/ajax": "^3.0.
|
|
12
|
+
"@subiz/ajax": "^3.0.22",
|
|
13
13
|
"@subiz/flow": "^1.1.0",
|
|
14
14
|
"@subiz/wsclient": "^4.0.34",
|
|
15
15
|
"cookie_js": "1.4.2",
|
|
16
|
-
"core-js": "^3.
|
|
16
|
+
"core-js": "^3.47.0",
|
|
17
17
|
"css-loader": "5.2.7",
|
|
18
18
|
"file-loader": "^6.2.0",
|
|
19
|
-
"less": "^4.
|
|
19
|
+
"less": "^4.5.1",
|
|
20
20
|
"less-loader": "^12.3.0",
|
|
21
21
|
"preact": "10.19.3"
|
|
22
22
|
},
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"@babel/preset-env": "^7.28.5",
|
|
29
29
|
"babel-loader": "^10.0.0",
|
|
30
30
|
"babel-plugin-syntax-jsx": "^6.18.0",
|
|
31
|
-
"html-webpack-plugin": "^5.6.
|
|
32
|
-
"puppeteer": "^24.
|
|
33
|
-
"webpack": "^5.
|
|
34
|
-
"webpack-bundle-analyzer": "^
|
|
31
|
+
"html-webpack-plugin": "^5.6.5",
|
|
32
|
+
"puppeteer": "^24.34.0",
|
|
33
|
+
"webpack": "^5.104.1",
|
|
34
|
+
"webpack-bundle-analyzer": "^5.1.0",
|
|
35
35
|
"webpack-cli": "^6.0.1",
|
|
36
36
|
"webpack-dev-server": "^5.2.2"
|
|
37
37
|
}
|
package/src/chatbox/Event.js
CHANGED
|
@@ -28,6 +28,26 @@ export default class Event extends Com {
|
|
|
28
28
|
this.props.store.onConvoEvent(this, (ev) => this.onEvent(ev))
|
|
29
29
|
this.refForm = createRef()
|
|
30
30
|
this.state = {pongs: sb.get(this.props.event, 'ev.data.message.pongs') || []}
|
|
31
|
+
this.textMessageRef = createRef()
|
|
32
|
+
this.fileAttachmentRef = createRef()
|
|
33
|
+
this.imageAttachmentRef = createRef()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
focusSourceEventFromQuote = (ev) => {
|
|
37
|
+
let $textMessage = this.textMessageRef.current
|
|
38
|
+
if ($textMessage && typeof $textMessage.focusSourceEventFromQuote === 'function') {
|
|
39
|
+
$textMessage.focusSourceEventFromQuote(ev)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let $fileAttachment = this.fileAttachmentRef.current
|
|
43
|
+
if ($fileAttachment && typeof $fileAttachment.focusSourceEventFromQuote === 'function') {
|
|
44
|
+
$fileAttachment.focusSourceEventFromQuote(ev)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let $imageAttachment = this.imageAttachmentRef.current
|
|
48
|
+
if ($imageAttachment && typeof $imageAttachment.focusSourceEventFromQuote === 'function') {
|
|
49
|
+
$imageAttachment.focusSourceEventFromQuote(ev)
|
|
50
|
+
}
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
render() {
|
|
@@ -248,21 +268,34 @@ export default class Event extends Com {
|
|
|
248
268
|
let wrappercls = 'agent-convo-event-wrapper'
|
|
249
269
|
if (hasForm) wrappercls += ' full'
|
|
250
270
|
return (
|
|
251
|
-
<div class='convo-event agent-message'>
|
|
271
|
+
<div class='convo-event agent-message' data-ev-id={ev.id}>
|
|
252
272
|
{$sender}
|
|
253
273
|
<div class={wrappercls}>
|
|
254
274
|
<div class={innercls}>
|
|
255
275
|
<TextMessage
|
|
276
|
+
ref={this.textMessageRef}
|
|
277
|
+
onFocusSourceEventFromQuote={this.props.onFocusSourceEventFromQuote}
|
|
256
278
|
showTime={this.props.event.show_time}
|
|
257
279
|
isLast={this.props.isLast}
|
|
258
280
|
store={this.props.store}
|
|
281
|
+
t={this.props.t}
|
|
259
282
|
ev={ev}
|
|
260
283
|
onLink={this.props.onLink}
|
|
261
284
|
/>
|
|
262
|
-
<ImageAttachments
|
|
285
|
+
<ImageAttachments
|
|
286
|
+
ref={this.imageAttachmentRef}
|
|
287
|
+
store={this.props.store}
|
|
288
|
+
ev={ev}
|
|
289
|
+
focusSourceEventFromQuote={this.props.focusSourceEventFromQuote}
|
|
290
|
+
/>
|
|
263
291
|
<AudioAttachments store={this.props.store} ev={ev} />
|
|
264
292
|
<VideoAttachments store={this.props.store} ev={ev} />
|
|
265
|
-
<FileAttachments
|
|
293
|
+
<FileAttachments
|
|
294
|
+
ref={this.fileAttachmentRef}
|
|
295
|
+
store={this.props.store}
|
|
296
|
+
ev={ev}
|
|
297
|
+
focusSourceEventFromQuote={this.props.focusSourceEventFromQuote}
|
|
298
|
+
/>
|
|
266
299
|
<ButtonAttachments store={this.props.store} ev={ev} t={this.props.t} />
|
|
267
300
|
<FormAttachment store={this.props.store} ev={ev} t={this.props.t} />
|
|
268
301
|
<FormSubmitAttachments store={this.props.store} ev={ev} t={this.props.t} />
|
|
@@ -317,15 +350,21 @@ export default class Event extends Com {
|
|
|
317
350
|
}
|
|
318
351
|
|
|
319
352
|
return (
|
|
320
|
-
<div class='convo-event user-message'>
|
|
353
|
+
<div class='convo-event user-message' data-ev-id={ev.id}>
|
|
321
354
|
{$sender}
|
|
322
355
|
<div class='message-user__container'>
|
|
323
356
|
{$dot}
|
|
324
|
-
<TextMessage
|
|
325
|
-
|
|
357
|
+
<TextMessage
|
|
358
|
+
ref={this.textMessageRef}
|
|
359
|
+
store={this.props.store}
|
|
360
|
+
ev={ev}
|
|
361
|
+
refresh={this.state.refresh}
|
|
362
|
+
onLink={this.props.onLink}
|
|
363
|
+
/>
|
|
364
|
+
<ImageAttachments store={this.props.store} ev={ev} ref={this.imageAttachmentRef} />
|
|
326
365
|
<AudioAttachments store={this.props.store} ev={ev} />
|
|
327
366
|
<VideoAttachments store={this.props.store} ev={ev} />
|
|
328
|
-
<FileAttachments store={this.props.store} ev={ev} />
|
|
367
|
+
<FileAttachments store={this.props.store} ev={ev} ref={this.fileAttachmentRef} />
|
|
329
368
|
<ButtonAttachments store={this.props.store} ev={ev} t={this.props.t} />
|
|
330
369
|
<FormAttachment store={this.props.store} t={this.props.t} ev={ev} />
|
|
331
370
|
<ProductAttachments t={this.props.t} store={this.props.store} ev={ev} />
|
|
@@ -388,6 +427,8 @@ export default class Event extends Com {
|
|
|
388
427
|
let cid = sb.get(this.props.event.ev, 'data.message.conversation_id', '')
|
|
389
428
|
if (cid.startsWith('cslight')) return null
|
|
390
429
|
let ev = sb.get(this.props.event, 'ev') || {}
|
|
430
|
+
let isDeleted = sb.get(ev, 'data.message.deleted')
|
|
431
|
+
if (isDeleted) return
|
|
391
432
|
let pongs = sb.get(ev, 'data.message.pongs') || []
|
|
392
433
|
let hasLike = this.hasLike()
|
|
393
434
|
let hasDislike = this.hasDislike()
|
|
@@ -425,7 +466,6 @@ export default class Event extends Com {
|
|
|
425
466
|
}
|
|
426
467
|
|
|
427
468
|
renderAIDevNote() {
|
|
428
|
-
if (!this.props.isLast) return null
|
|
429
469
|
if (!this.props.store.isAIDevMode()) return null
|
|
430
470
|
let cid = sb.get(this.props.event.ev, 'data.message.conversation_id', '')
|
|
431
471
|
if (cid.startsWith('cslight')) return null
|
|
@@ -440,7 +480,7 @@ export default class Event extends Com {
|
|
|
440
480
|
if (hasDislike) dislikecls += ' active'
|
|
441
481
|
|
|
442
482
|
return (
|
|
443
|
-
<div class='message-event-actions'>
|
|
483
|
+
<div class='message-event-actions-static'>
|
|
444
484
|
<div class={likecls} onClick={() => this.onSendReaction(hasLike ? 'remove_like' : 'like')}>
|
|
445
485
|
<div class='message-event-action-btn-svg like' /> Good
|
|
446
486
|
</div>
|
package/src/chatbox/Events.js
CHANGED
|
@@ -5,7 +5,7 @@ import sb from '../util/index.js'
|
|
|
5
5
|
|
|
6
6
|
import Spinner from './spinner.js'
|
|
7
7
|
import {Com} from '../common.js'
|
|
8
|
-
import {h, Fragment} from 'preact'
|
|
8
|
+
import {h, Fragment, createRef} from 'preact'
|
|
9
9
|
|
|
10
10
|
// ['cid', 'creating', 'isShow'],
|
|
11
11
|
export default class Events extends Com {
|
|
@@ -15,6 +15,7 @@ export default class Events extends Com {
|
|
|
15
15
|
this.props.store.onConvoEvent(this, (ev) => this.onEvent(ev))
|
|
16
16
|
this.loadConvo()
|
|
17
17
|
this.refBody = null
|
|
18
|
+
this.evRefs = {}
|
|
18
19
|
|
|
19
20
|
this.checkAndSeen = sb.throttle(() => {
|
|
20
21
|
if (
|
|
@@ -64,12 +65,29 @@ export default class Events extends Com {
|
|
|
64
65
|
this.setState({isShowTyping: false})
|
|
65
66
|
}, 5000)
|
|
66
67
|
})
|
|
68
|
+
|
|
69
|
+
this.props.store.onMessageUpdated(this, async (ev) => {
|
|
70
|
+
if (sb.convoOfEv(ev) !== this.props.cid) return
|
|
71
|
+
await this.props.store.reloadConvoEvents(this.props.cid)
|
|
72
|
+
this.forceUpdate()
|
|
73
|
+
})
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
componentDidUpdate(prevProps) {
|
|
70
77
|
if (prevProps.cid !== this.props.cid) this.loadConvo()
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
setEventChildRef(ele, id) {
|
|
81
|
+
this.evRefs[id] = ele
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onFocusSourceEventFromQuote = (ev) => {
|
|
85
|
+
let ref = this.evRefs[ev.id]
|
|
86
|
+
if (ref) {
|
|
87
|
+
ref.focusSourceEventFromQuote(ev)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
73
91
|
ShowTyping() {
|
|
74
92
|
this.setState({
|
|
75
93
|
isShowTyping: true,
|
|
@@ -140,6 +158,8 @@ export default class Events extends Com {
|
|
|
140
158
|
onFormSubmit={this.props.onFormSubmit}
|
|
141
159
|
onSend={this.props.onSend}
|
|
142
160
|
onPostback={this.props.onPostback}
|
|
161
|
+
onFocusSourceEventFromQuote={this.onFocusSourceEventFromQuote}
|
|
162
|
+
ref={(ele) => this.setEventChildRef(ele, ev.ev.id)}
|
|
143
163
|
event={ev}
|
|
144
164
|
t={this.props.t}
|
|
145
165
|
key={ev.ev.id}
|
|
@@ -3,12 +3,17 @@ import {Com} from '../common.js'
|
|
|
3
3
|
import {h} from 'preact'
|
|
4
4
|
|
|
5
5
|
export default class FileAttachments extends Com {
|
|
6
|
+
constructor(props) {
|
|
7
|
+
super(props)
|
|
8
|
+
this.state = {focusedIdx: -1}
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
render() {
|
|
7
12
|
var byType = sb.get(this.props.ev, 'by.type', 'agent')
|
|
8
13
|
if (byType !== 'user') byType = 'agent'
|
|
9
14
|
var attachments = sb.get(this.props.ev, 'data.message.attachments', [])
|
|
10
15
|
var files = []
|
|
11
|
-
sb.each(attachments, (att) => {
|
|
16
|
+
sb.each(attachments, (att, idx) => {
|
|
12
17
|
if (!att) return
|
|
13
18
|
if (!att.url && !att._file) return
|
|
14
19
|
if (
|
|
@@ -20,15 +25,18 @@ export default class FileAttachments extends Com {
|
|
|
20
25
|
att.type !== 'form' &&
|
|
21
26
|
att.type !== 'form_submit'
|
|
22
27
|
) {
|
|
23
|
-
files.push(att)
|
|
28
|
+
files.push({...att, _true_idx: idx})
|
|
24
29
|
}
|
|
25
30
|
})
|
|
26
31
|
|
|
27
32
|
if (files.length === 0) return null
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
let $files = sb.map(files, (file, index) => {
|
|
35
|
+
let cls = `file-attachment file-attachment--${byType}`
|
|
36
|
+
if (file._true_idx === this.state.focusedIdx) cls += ` just-focused`
|
|
37
|
+
|
|
30
38
|
return (
|
|
31
|
-
<div key={index} class={
|
|
39
|
+
<div key={index} class={cls}>
|
|
32
40
|
<a class='file-attachment--link' href={this.props.store.replaceFileUrl(file.url)} target='_blank'>
|
|
33
41
|
<span class='file-attachment--download mr-2'></span>
|
|
34
42
|
<span class='file-attachment--filename'>{file.name}</span>
|
|
@@ -39,4 +47,23 @@ export default class FileAttachments extends Com {
|
|
|
39
47
|
|
|
40
48
|
return <div class={`message-${byType}`}>{$files}</div>
|
|
41
49
|
}
|
|
50
|
+
|
|
51
|
+
focusSourceEventFromQuote(ev) {
|
|
52
|
+
if (ev.id !== this.props.ev.id) return
|
|
53
|
+
let fields = sb.get(ev, 'data.message.fields') || []
|
|
54
|
+
let attachmentIndexField = sb.find(fields, (f) => f.key === 'attachment_index')
|
|
55
|
+
let attachmentIndex = sb.get(attachmentIndexField, 'value')
|
|
56
|
+
try {
|
|
57
|
+
attachmentIndex = JSON.parse(attachmentIndex)
|
|
58
|
+
} catch (err) {
|
|
59
|
+
attachmentIndex = undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (attachmentIndex === undefined) return // this is a quote for text
|
|
63
|
+
this.setState({focusedIdx: attachmentIndex})
|
|
64
|
+
if (this.focusTimeout) clearTimeout(this.focusTimeout)
|
|
65
|
+
this.focusTimeout = setTimeout(() => {
|
|
66
|
+
this.setState({focusedIdx: -1})
|
|
67
|
+
}, 3000)
|
|
68
|
+
}
|
|
42
69
|
}
|
|
@@ -8,6 +8,7 @@ export default class ImageAttachment extends Com {
|
|
|
8
8
|
this.setState({
|
|
9
9
|
ready: false,
|
|
10
10
|
errorIndecies: [],
|
|
11
|
+
focusedIdx: -1,
|
|
11
12
|
})
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -16,6 +17,25 @@ export default class ImageAttachment extends Com {
|
|
|
16
17
|
this.setImageFrameDimension()
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
focusSourceEventFromQuote(ev) {
|
|
21
|
+
if (ev.id !== this.props.ev.id) return
|
|
22
|
+
let fields = sb.get(ev, 'data.message.fields') || []
|
|
23
|
+
let attachmentIndexField = sb.find(fields, (f) => f.key === 'attachment_index')
|
|
24
|
+
let attachmentIndex = sb.get(attachmentIndexField, 'value')
|
|
25
|
+
try {
|
|
26
|
+
attachmentIndex = JSON.parse(attachmentIndex)
|
|
27
|
+
} catch (err) {
|
|
28
|
+
attachmentIndex = undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (attachmentIndex === undefined) return // this is a quote for text
|
|
32
|
+
this.setState({focusedIdx: attachmentIndex})
|
|
33
|
+
if (this.focusTimeout) clearTimeout(this.focusTimeout)
|
|
34
|
+
this.focusTimeout = setTimeout(() => {
|
|
35
|
+
this.setState({focusedIdx: -1})
|
|
36
|
+
}, 3000)
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
setImageFrameDimension() {
|
|
20
40
|
const MAX_HEIGHT = 240
|
|
21
41
|
const DEFAULT_MAX_WIDTH = 267
|
|
@@ -60,9 +80,12 @@ export default class ImageAttachment extends Com {
|
|
|
60
80
|
let byType = sb.get(this.props.ev, 'by.type')
|
|
61
81
|
if (byType !== 'user') byType = 'agent'
|
|
62
82
|
|
|
83
|
+
let cls = `image-attachment image-attachment--${byType}`
|
|
84
|
+
if (image._true_idx === this.state.focusedIdx) cls += ' just-focused'
|
|
85
|
+
|
|
63
86
|
if (!image.width || !image.height) {
|
|
64
87
|
return (
|
|
65
|
-
<div class={
|
|
88
|
+
<div class={cls}>
|
|
66
89
|
<a href={this.props.store.replaceFileUrl(image.url)} target='_blank'>
|
|
67
90
|
<img
|
|
68
91
|
alt
|
|
@@ -84,7 +107,7 @@ export default class ImageAttachment extends Com {
|
|
|
84
107
|
}
|
|
85
108
|
|
|
86
109
|
return (
|
|
87
|
-
<div class={
|
|
110
|
+
<div class={cls}>
|
|
88
111
|
<a href={trueUrl} target='_blank'>
|
|
89
112
|
<img
|
|
90
113
|
alt
|
|
@@ -125,7 +148,7 @@ export default class ImageAttachment extends Com {
|
|
|
125
148
|
) {
|
|
126
149
|
att.url = this.props.store.FileURL + uri
|
|
127
150
|
}
|
|
128
|
-
images.push(att)
|
|
151
|
+
images.push({...att, _true_idx: i})
|
|
129
152
|
})
|
|
130
153
|
|
|
131
154
|
if (images.length === 0) return null
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import sb from '../util/index.js'
|
|
2
|
+
import Block from './block.js'
|
|
3
|
+
import {Com} from '../common.js'
|
|
4
|
+
import {h} from 'preact'
|
|
5
|
+
import Emoji from './Emoji.js'
|
|
6
|
+
|
|
7
|
+
export default class QuoteMessage extends Com {
|
|
8
|
+
render() {
|
|
9
|
+
let sendername = ''
|
|
10
|
+
let byType = sb.get(this.props.ev, 'by.type')
|
|
11
|
+
let byId = sb.get(this.props.ev, 'by.id')
|
|
12
|
+
|
|
13
|
+
if (byType === 'user') {
|
|
14
|
+
sendername = this.props.t('you')
|
|
15
|
+
} else {
|
|
16
|
+
sendername = this.getSenderName(this.props.ev)
|
|
17
|
+
|
|
18
|
+
let acc = this.props.store.matchAccount() || {}
|
|
19
|
+
if (sb.get(this.props, 'chatbox.hide_agent_profile')) sendername = acc.name
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let att = sb.get(this.props.ev, 'data.message.attachments.0')
|
|
23
|
+
if (att) {
|
|
24
|
+
let isImg = sb.includes(att.mimetype, 'image')
|
|
25
|
+
if (isImg) {
|
|
26
|
+
let uri = att.url
|
|
27
|
+
if (
|
|
28
|
+
!uri.startsWith('https://') &&
|
|
29
|
+
!uri.startsWith('http://') &&
|
|
30
|
+
!uri.startsWith('content://') &&
|
|
31
|
+
!uri.startsWith('data:')
|
|
32
|
+
) {
|
|
33
|
+
uri = this.props.store.FileURL + uri
|
|
34
|
+
}
|
|
35
|
+
return (
|
|
36
|
+
<div class='message-quote d-flex' onClick={() => this.scrollToSourceEvent(this.props.ev)}>
|
|
37
|
+
<img src={uri} class='message-quote-inner-img' />
|
|
38
|
+
<div class='message-quote-inner'>
|
|
39
|
+
<div class='message-quote-title'>{sendername}</div>
|
|
40
|
+
<div class='message-quote-content'>[{this.props.t('image')}]</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
} else {
|
|
45
|
+
return (
|
|
46
|
+
<div class='message-quote' onClick={() => this.scrollToSourceEvent(this.props.ev)}>
|
|
47
|
+
<div class='message-quote-title'>{sendername}</div>
|
|
48
|
+
<div class='message-quote-content'>
|
|
49
|
+
{`[File] `}
|
|
50
|
+
{att.name}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let format = sb.get(this.props.ev, 'data.message.format', 'plaintext')
|
|
58
|
+
let block = sb.get(this.props.ev, 'data.message.block')
|
|
59
|
+
|
|
60
|
+
let text = sb.get(this.props.ev, 'data.message.text')
|
|
61
|
+
if (block) text = sb.blockToText(block)
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div class='message-quote' onClick={() => this.scrollToSourceEvent(this.props.ev)}>
|
|
65
|
+
<div class='message-quote-title'>{sendername}</div>
|
|
66
|
+
<div class='message-quote-content'>{text}</div>
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
scrollToSourceEvent(ev) {
|
|
72
|
+
let $ele = document.querySelector(`.convo-event[data-ev-id=${ev.id}]`)
|
|
73
|
+
if ($ele && typeof $ele.scrollIntoViewIfNeeded === 'function') {
|
|
74
|
+
$ele.scrollIntoViewIfNeeded()
|
|
75
|
+
}
|
|
76
|
+
this.props.onFocusSourceEventFromQuote(ev)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getSenderName = (ev) => {
|
|
80
|
+
let bytype = sb.get(ev, 'by.type')
|
|
81
|
+
let byid = sb.get(ev, 'by.display_id', sb.get(ev, 'by.id')) || ''
|
|
82
|
+
if (bytype === 'user') return sb.getUserDisplayName(this.props.store.matchUser())
|
|
83
|
+
let acc = this.props.store.matchAccount()
|
|
84
|
+
if (bytype === 'agent') return sb.getAgentDisplayName(acc, this.props.store.matchAgent(byid))
|
|
85
|
+
if (byid.startsWith('at')) return sb.getAgentDisplayName(acc, this.props.store.matchAgent(byid))
|
|
86
|
+
if (bytype === 'bot') {
|
|
87
|
+
let bot = this.props.store.matchBot()[byid]
|
|
88
|
+
if (!bot) return 'Bot'
|
|
89
|
+
return bot.fullname || 'Bot'
|
|
90
|
+
}
|
|
91
|
+
if (byid === 'system' || bytype === 'dummy' || bytype === 'workflow') return acc.name || 'system'
|
|
92
|
+
return acc.name
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/chatbox/Rating.js
CHANGED
|
@@ -34,6 +34,11 @@ export default class Rating extends Com {
|
|
|
34
34
|
this.props.store.onConvoEvent(this, (ev) => {
|
|
35
35
|
var cid = sb.convoOfEv(ev)
|
|
36
36
|
if (cid !== this.props.cid) return
|
|
37
|
+
if (!this.state.hide && ev.type === 'conversation_rated') {
|
|
38
|
+
// close if already rated in another tab
|
|
39
|
+
this.close()
|
|
40
|
+
return
|
|
41
|
+
}
|
|
37
42
|
if (this.shoudDisplay()) this.open()
|
|
38
43
|
})
|
|
39
44
|
|
|
@@ -4,8 +4,14 @@ import {Com} from '../common.js'
|
|
|
4
4
|
import {h} from 'preact'
|
|
5
5
|
import Emoji from './Emoji.js'
|
|
6
6
|
import Time from './time.js'
|
|
7
|
+
import QuoteMessage from './QuoteMessage.js'
|
|
7
8
|
|
|
8
9
|
export default class TextMessage extends Com {
|
|
10
|
+
constructor(props) {
|
|
11
|
+
super(props)
|
|
12
|
+
this.state = {focused: false}
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
renderTime() {
|
|
10
16
|
return null
|
|
11
17
|
if (!this.props.showTime && !this.props.isLast && !this.props.isFirst) return null
|
|
@@ -17,6 +23,25 @@ export default class TextMessage extends Com {
|
|
|
17
23
|
)
|
|
18
24
|
}
|
|
19
25
|
|
|
26
|
+
focusSourceEventFromQuote(ev) {
|
|
27
|
+
if (ev.id !== this.props.ev.id) return
|
|
28
|
+
let fields = sb.get(ev, 'data.message.fields') || []
|
|
29
|
+
let attachmentIndexField = sb.find(fields, (f) => f.key === 'attachment_index')
|
|
30
|
+
let attachmentIndex = sb.get(attachmentIndexField, 'value')
|
|
31
|
+
try {
|
|
32
|
+
attachmentIndex = JSON.parse(attachmentIndex)
|
|
33
|
+
} catch (err) {
|
|
34
|
+
attachmentIndex = undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (attachmentIndex !== undefined) return // this is a quote for image or video, not for text
|
|
38
|
+
this.setState({focused: true})
|
|
39
|
+
if (this.focusTimeout) clearTimeout(this.focusTimeout)
|
|
40
|
+
this.focusTimeout = setTimeout(() => {
|
|
41
|
+
this.setState({focused: false})
|
|
42
|
+
}, 3000)
|
|
43
|
+
}
|
|
44
|
+
|
|
20
45
|
render() {
|
|
21
46
|
var format = sb.get(this.props.ev, 'data.message.format', 'plaintext')
|
|
22
47
|
let block = sb.get(this.props.ev, 'data.message.block')
|
|
@@ -66,15 +91,38 @@ export default class TextMessage extends Com {
|
|
|
66
91
|
})
|
|
67
92
|
|
|
68
93
|
if (sb.size(tags) === 0) return null
|
|
69
|
-
|
|
94
|
+
let isDeleted = sb.get(this.props.ev, 'data.message.deleted')
|
|
95
|
+
|
|
96
|
+
let attachments = sb.get(this.props.ev, 'data.message.attachments', [])
|
|
97
|
+
let quote = sb.find(attachments, (att) => att.type === 'quote')
|
|
98
|
+
|
|
99
|
+
if (byType === 'agent') {
|
|
100
|
+
let cls = 'message-agent message-text--agent'
|
|
101
|
+
if (isDeleted) {
|
|
102
|
+
tags = this.props.t('recalled_message')
|
|
103
|
+
cls += ' message-text--deleted'
|
|
104
|
+
}
|
|
105
|
+
if (this.state.focused) cls += ' just-focused'
|
|
106
|
+
|
|
70
107
|
return (
|
|
71
|
-
<div class=
|
|
108
|
+
<div class={cls} title={t}>
|
|
109
|
+
{quote && (
|
|
110
|
+
<QuoteMessage
|
|
111
|
+
ev={sb.get(quote, 'quote')}
|
|
112
|
+
t={this.props.t}
|
|
113
|
+
store={this.props.store}
|
|
114
|
+
onFocusSourceEventFromQuote={this.props.onFocusSourceEventFromQuote}
|
|
115
|
+
/>
|
|
116
|
+
)}
|
|
72
117
|
{tags}
|
|
73
118
|
{this.renderTime()}
|
|
74
119
|
</div>
|
|
75
120
|
)
|
|
121
|
+
}
|
|
76
122
|
let msgcls = 'message-user message-text--user'
|
|
77
123
|
if (this.props.ev._error) msgcls += ' message-user--error'
|
|
124
|
+
if (this.state.focused) msgcls += ' just-focused'
|
|
125
|
+
|
|
78
126
|
return (
|
|
79
127
|
<div class={msgcls} title={t}>
|
|
80
128
|
{tags}
|
package/src/chatbox/Widget.js
CHANGED
|
@@ -48,6 +48,54 @@ export default class Widget extends Com {
|
|
|
48
48
|
if (!this.props.store.isMobile()) this.focusInput()
|
|
49
49
|
|
|
50
50
|
this.updateFormDataFields()
|
|
51
|
+
this.debugRTAgentMessageSent()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
findMissingRTMessage = async (started) => {
|
|
55
|
+
let messageSentDict = this.props.store.listAgentRealtimeMessageSent()
|
|
56
|
+
|
|
57
|
+
let res1 = await this.props.store.sbzListConversations()
|
|
58
|
+
let conversions = sb.get(res1, 'body.conversations') || []
|
|
59
|
+
let cids = sb.map(conversions, (convo) => convo.id)
|
|
60
|
+
|
|
61
|
+
let promises = sb.map(cids, (cid) => this.props.store.sbzListMessages(cid))
|
|
62
|
+
let msgReses = await Promise.all(promises)
|
|
63
|
+
sb.map(msgReses, (msgRes) => {
|
|
64
|
+
let messages = sb.get(msgRes, 'body') || []
|
|
65
|
+
sb.map(messages, (ev) => {
|
|
66
|
+
if (ev.created < started) return
|
|
67
|
+
//if (ev.created > Date.now() - 30_000) return
|
|
68
|
+
if (ev.type !== 'message_sent') return
|
|
69
|
+
if (sb.get(ev, 'by.type') === 'user') return
|
|
70
|
+
|
|
71
|
+
console.log('check ev pass condition', ev)
|
|
72
|
+
if (!messageSentDict[ev.id]) {
|
|
73
|
+
this.props.store.sendBugReport(
|
|
74
|
+
'[WIDGET ' + accid + '] Missing agent message sent evid ' + ev.id + ', cid ' + sb.convoOfEv(ev),
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
debugRTAgentMessageSent = async () => {
|
|
82
|
+
try {
|
|
83
|
+
let debugAccountIds = this.props.store.matchDebugAccountIds()
|
|
84
|
+
let accid = sb.get(this.props.store.matchAccount(), 'id')
|
|
85
|
+
if (!debugAccountIds.includes(accid)) return
|
|
86
|
+
|
|
87
|
+
console.log('START check RT agent message with BE source')
|
|
88
|
+
let started = Date.now()
|
|
89
|
+
this.findMissingRTMessage(started)
|
|
90
|
+
|
|
91
|
+
for (let i = 0; i < 100_000; i++) {
|
|
92
|
+
await sb.sleep(120_000)
|
|
93
|
+
console.log('LOOP check RT agent message with BE source', i)
|
|
94
|
+
this.findMissingRTMessage(started)
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
this.props.store.sendBugReport(`debugRTAgentMessageSent ERROR ${err.stack}`)
|
|
98
|
+
}
|
|
51
99
|
}
|
|
52
100
|
|
|
53
101
|
applyMessage(text) {
|
|
@@ -799,6 +847,9 @@ export default class Widget extends Com {
|
|
|
799
847
|
this.setState({creating: true})
|
|
800
848
|
let botid = cid.split('_')[0].slice(7) // 6 = len(cslight)
|
|
801
849
|
let oldconvo = this.props.store.matchConvo(this.props.cid) || {}
|
|
850
|
+
let greeting_msg = sb.find(oldconvo.events, (ev) => {
|
|
851
|
+
return ev.type == 'message_sent' && ev.by && ev.by.type == 'bot'
|
|
852
|
+
})
|
|
802
853
|
const {convo, error} = await this.props.store.startConvo({
|
|
803
854
|
state: 'active', // so it would not run through rule
|
|
804
855
|
locale: this.props.t.locale(),
|
|
@@ -806,6 +857,7 @@ export default class Widget extends Com {
|
|
|
806
857
|
members: [{type: 'bot', id: botid, bot_version: oldconvo.bot_version}],
|
|
807
858
|
initial_by: this.props.store.matchUser().id,
|
|
808
859
|
is_testing: oldconvo.is_testing,
|
|
860
|
+
greeting_message: greeting_msg,
|
|
809
861
|
})
|
|
810
862
|
if (_creating != this._creating) return // outdated
|
|
811
863
|
if (error) {
|
package/src/store/api.js
CHANGED
|
@@ -39,6 +39,7 @@ export default class {
|
|
|
39
39
|
|
|
40
40
|
this.FileURL = FileURL
|
|
41
41
|
this.ApiURL = ApiURL
|
|
42
|
+
this.bugReq = ajax.setBaseUrl('https://api5.subiz.com.vn/4.1').setContentType('text/plain')
|
|
42
43
|
this.api41 = ajax
|
|
43
44
|
.setBaseUrl('https://api.sbz.vn/4.1')
|
|
44
45
|
.withCredentials(true)
|
|
@@ -229,6 +230,8 @@ export default class {
|
|
|
229
230
|
return {error: 'invalid_auth'}
|
|
230
231
|
}
|
|
231
232
|
|
|
233
|
+
sendBugReport = (str) => this.bugReq.post('/bugs', str)
|
|
234
|
+
|
|
232
235
|
listConversations = (_) =>
|
|
233
236
|
this.apireq
|
|
234
237
|
.addQuery('user_id', this.uid)
|