@subiz/widget-v4 4.1.210 → 4.1.211
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/README.md +21 -2
- package/assets/less/chatbox.less +9 -0
- package/assets/less/form.less +10 -0
- package/assets/less/message.less +114 -13
- package/assets/less/widget.less +21 -16
- package/compiled_src/call/css.js +1 -1
- package/compiled_src/chatbox/Buttons.js +7 -4
- package/compiled_src/chatbox/ChatButton.js +115 -29
- package/compiled_src/chatbox/Event.js +37 -5
- package/compiled_src/chatbox/Events.js +348 -129
- package/compiled_src/chatbox/FormAttachment.js +1 -1
- package/compiled_src/chatbox/Header.js +6 -2
- package/compiled_src/chatbox/InfoMessage.js +1 -1
- package/compiled_src/chatbox/MessageInput.js +24 -9
- package/compiled_src/chatbox/OrderAttachments.js +13 -13
- package/compiled_src/chatbox/QuoteMessage.js +3 -2
- package/compiled_src/chatbox/TextMessage.js +22 -18
- package/compiled_src/chatbox/Widget.js +200 -129
- package/compiled_src/chatbox/block.js +39 -29
- package/compiled_src/chatbox/conversation-history.js +44 -0
- package/compiled_src/chatbox/event-layout.js +59 -0
- package/compiled_src/chatbox/greeting.js +32 -0
- package/compiled_src/common.js +13 -9
- package/compiled_src/form/css.js +1 -1
- package/compiled_src/lib.js +22 -32
- package/compiled_src/notif/css.js +1 -1
- package/compiled_src/plugin.js +11 -18
- package/compiled_src/popup/css.js +1 -1
- package/compiled_src/popup/popup.js +1 -1
- package/compiled_src/store/api.js +0 -2
- package/compiled_src/store/api_fake.js +1 -1
- package/compiled_src/store/attachments.js +28 -0
- package/compiled_src/store/chain.js +24 -10
- package/compiled_src/store/kv.js +9 -13
- package/compiled_src/store/lsdb.js +1 -1
- package/compiled_src/store/store.js +356 -117
- package/compiled_src/util/common.js +48 -41
- package/compiled_src/util/event.js +15 -0
- package/compiled_src/util/pubsub.js +28 -13
- package/compiled_src/util/url.js +18 -0
- package/dist/.HASH +1 -0
- package/dist/127.js +13 -13
- package/dist/132.js +1 -1
- package/dist/1a0ddc53cbb.127.js +1 -0
- package/dist/{1a0d80f6e72.132.js → 1a0ddc53cbb.132.js} +1 -1
- package/dist/1a0ddc53cbb.278.js +1 -0
- package/dist/{1a0d80f6e72.339.js → 1a0ddc53cbb.339.js} +1 -1
- package/dist/1a0ddc53cbb.app.js +1 -0
- package/dist/{1a0d80f6e72.chat.html → 1a0ddc53cbb.chat.html} +1 -1
- package/dist/1a0ddc53cbb.chat.js +1 -0
- package/dist/{1a0d80f6e72.form.html → 1a0ddc53cbb.form.html} +1 -1
- package/dist/1a0ddc53cbb.form.js +1 -0
- package/dist/{1a0d80f6e72.index.html → 1a0ddc53cbb.index.html} +1 -1
- package/dist/{1a0d80f6e72.library.html → 1a0ddc53cbb.library.html} +1 -1
- package/dist/1a0ddc53cbb.library.js +1 -0
- package/dist/{1a0d80f6e72.preview.html → 1a0ddc53cbb.preview.html} +1 -1
- package/dist/1a0ddc53cbb.preview.js +1 -0
- package/dist/1a0ddc53cbb.webview.js +1 -0
- package/dist/screenshoot.js +1492 -616
- package/package.json +10 -3
- package/src/chatbox/Buttons.js +5 -4
- package/src/chatbox/ChatButton.js +120 -39
- package/src/chatbox/Event.js +38 -5
- package/src/chatbox/Events.js +306 -134
- package/src/chatbox/FormAttachment.js +1 -1
- package/src/chatbox/Header.js +4 -4
- package/src/chatbox/InfoMessage.js +1 -1
- package/src/chatbox/MessageInput.js +15 -10
- package/src/chatbox/OrderAttachments.js +13 -13
- package/src/chatbox/QuoteMessage.js +3 -2
- package/src/chatbox/TextMessage.js +21 -20
- package/src/chatbox/Widget.js +150 -150
- package/src/chatbox/block.js +29 -27
- package/src/chatbox/conversation-history.js +37 -0
- package/src/chatbox/event-layout.js +72 -0
- package/src/chatbox/greeting.js +13 -0
- package/src/common.js +15 -9
- package/src/lib.js +22 -35
- package/src/plugin.js +11 -13
- package/src/popup/popup.js +1 -1
- package/src/store/api.js +0 -2
- package/src/store/api_fake.js +1 -1
- package/src/store/attachments.js +21 -0
- package/src/store/chain.js +25 -12
- package/src/store/kv.js +10 -19
- package/src/store/lsdb.js +1 -1
- package/src/store/store.js +313 -130
- package/src/util/common.js +48 -43
- package/src/util/event.js +7 -0
- package/src/util/pubsub.js +27 -8
- package/src/util/url.js +14 -0
- package/test.cjs +59 -0
- package/assets/less/contact.less +0 -126
- package/compiled_src/util/common.test.js +0 -414
- package/compiled_src/util/event.test.js +0 -38
- package/compiled_src/util/extractor.test.js +0 -299
- package/compiled_src/util/extractor.test2.js +0 -61
- package/compiled_src/util/gate.test.js +0 -18
- package/compiled_src/util/pubsub.test.js +0 -35
- package/dist/1a0d80f6e72.127.js +0 -1
- package/dist/1a0d80f6e72.278.js +0 -1
- package/dist/1a0d80f6e72.74.js +0 -1
- package/dist/1a0d80f6e72.997.js +0 -1
- package/dist/1a0d80f6e72.app.js +0 -1
- package/dist/1a0d80f6e72.chat.js +0 -1
- package/dist/1a0d80f6e72.form.js +0 -1
- package/dist/1a0d80f6e72.library.js +0 -1
- package/dist/1a0d80f6e72.preview.js +0 -1
- package/dist/1a0d80f6e72.webview.js +0 -1
- package/dist/74.js +0 -376
- package/dist/997.js +0 -37
- package/dist/HASH +0 -1
- package/src/contact/contact.js +0 -400
- package/src/contact/css.js +0 -1
- package/src/util/common.test.js +0 -301
- package/src/util/event.test.js +0 -31
- package/src/util/extractor.test.js +0 -240
- package/src/util/extractor.test2.js +0 -56
- package/src/util/gate.test.js +0 -20
- package/src/util/pubsub.test.js +0 -37
- /package/dist/{1a0d80f6e72.185.js → 1a0ddc53cbb.185.js} +0 -0
- /package/dist/{1a0d80f6e72.27.js → 1a0ddc53cbb.27.js} +0 -0
- /package/dist/{1a0d80f6e72.459.js → 1a0ddc53cbb.459.js} +0 -0
- /package/dist/{1a0d80f6e72.490.js → 1a0ddc53cbb.490.js} +0 -0
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subiz/widget-v4",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.211",
|
|
4
4
|
"main": "./compiled_src/lib.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npx webpack serve --config webpack.dev.js",
|
|
7
|
-
"build": "rm -rf dist &&
|
|
7
|
+
"build": "npm run lib && rm -rf dist && webpack --config webpack.screenshoot.js && webpack --config webpack.prod.js",
|
|
8
8
|
"report": "npx webpack --config webpack.report.js",
|
|
9
|
-
"lib": "
|
|
9
|
+
"lib": "babel src --out-dir compiled_src --ignore \"**/*.test.js,**/*.test2.js\"",
|
|
10
|
+
"test": "node test.cjs",
|
|
11
|
+
"lint": "eslint src",
|
|
12
|
+
"check": "npm run lint && npm test",
|
|
13
|
+
"prepack": "npm run check && npm run lib"
|
|
10
14
|
},
|
|
11
15
|
"dependencies": {
|
|
12
16
|
"@subiz/ajax": "^3.0.22",
|
|
@@ -28,7 +32,10 @@
|
|
|
28
32
|
"@babel/preset-env": "^7.29.7",
|
|
29
33
|
"babel-loader": "^10.1.1",
|
|
30
34
|
"babel-plugin-syntax-jsx": "^6.18.0",
|
|
35
|
+
"eslint": "^10.11.0",
|
|
36
|
+
"globals": "^17.12.0",
|
|
31
37
|
"html-webpack-plugin": "^5.6.8",
|
|
38
|
+
"jsdom": "^30.1.1",
|
|
32
39
|
"puppeteer": "^25.12.0",
|
|
33
40
|
"tape": "^5.10.2",
|
|
34
41
|
"webpack": "^5.111.1",
|
package/src/chatbox/Buttons.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import sb from '../util/index.js'
|
|
2
2
|
import {h} from 'preact'
|
|
3
|
+
import {safeUrl} from '../util/url.js'
|
|
3
4
|
|
|
4
5
|
export default function Buttons(props) {
|
|
5
6
|
if (sb.size(props.buttons) === 0) return null
|
|
6
7
|
var $buttons = sb.map(props.buttons, (button, index) => {
|
|
7
8
|
if (button.type === 'call_button') {
|
|
8
9
|
return (
|
|
9
|
-
<a class='url-button-attachment' href={'tel:' + button.phone_number} key={index} title={button.title}>
|
|
10
|
+
<a class='url-button-attachment' href={safeUrl('tel:' + button.phone_number)} key={index} title={button.title}>
|
|
10
11
|
{props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || `${props.t('call')} ${button.phone_number}`}
|
|
11
12
|
</a>
|
|
12
13
|
)
|
|
@@ -14,7 +15,7 @@ export default function Buttons(props) {
|
|
|
14
15
|
|
|
15
16
|
if (button.type === 'url_button') {
|
|
16
17
|
return (
|
|
17
|
-
<a class='url-button-attachment' href={button.url} target='_blank' key={index} title={button.title}>
|
|
18
|
+
<a class='url-button-attachment' href={safeUrl(button.url) || undefined} target='_blank' rel='noopener noreferrer' key={index} title={button.title}>
|
|
18
19
|
{props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || button.url}
|
|
19
20
|
</a>
|
|
20
21
|
)
|
|
@@ -22,9 +23,9 @@ export default function Buttons(props) {
|
|
|
22
23
|
|
|
23
24
|
if (button.type === 'postback_button') {
|
|
24
25
|
return (
|
|
25
|
-
<
|
|
26
|
+
<button type='button' class='url-button-attachment' key={index} onClick={(_) => props.onSelect(button)}>
|
|
26
27
|
{props.t.i18n(button.i18n_title) || button.title}
|
|
27
|
-
</
|
|
28
|
+
</button>
|
|
28
29
|
)
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -378,30 +378,7 @@ export default class ChatButton extends Com {
|
|
|
378
378
|
)
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
|
|
382
|
-
let accountSetting = this.props.plugin.chatbox
|
|
383
|
-
accountSetting = this.fixMissingSetting(accountSetting)
|
|
384
|
-
let imgsrc =
|
|
385
|
-
sb.get(accountSetting, 'desktop_button.background_image_url') ||
|
|
386
|
-
sb.get(accountSetting, 'desktop_button.background_mask_url') ||
|
|
387
|
-
defaultBubble
|
|
388
|
-
|
|
389
|
-
if (this.props.store.isMobile()) {
|
|
390
|
-
imgsrc =
|
|
391
|
-
sb.get(accountSetting, 'mobile_button.background_image_url') ||
|
|
392
|
-
sb.get(accountSetting, 'mobile_button.background_mask_url') ||
|
|
393
|
-
imgsrc
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
imgsrc = this.props.store.replaceFileUrl(imgsrc)
|
|
397
|
-
await sb.preloadImg(imgsrc)
|
|
398
|
-
this.setState({ready: true})
|
|
399
|
-
this.readyGate.open()
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
renderButton() {
|
|
403
|
-
if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_button = sb.Date.now()
|
|
404
|
-
|
|
381
|
+
getButtonAppearance() {
|
|
405
382
|
let accountSetting = this.props.plugin.chatbox
|
|
406
383
|
accountSetting = this.fixMissingSetting(accountSetting)
|
|
407
384
|
let imgsrc =
|
|
@@ -433,24 +410,88 @@ export default class ChatButton extends Com {
|
|
|
433
410
|
}
|
|
434
411
|
}
|
|
435
412
|
|
|
413
|
+
const imageUrl = (url) => addVersionParam(this.props.store.replaceFileUrl(url))
|
|
414
|
+
imgsrc = imageUrl(imgsrc)
|
|
415
|
+
imgurl = imageUrl(imgurl)
|
|
416
|
+
maskurl = imageUrl(maskurl)
|
|
417
|
+
const defaultMask = !imgurl && !maskurl ? DEF_BG_URL : ''
|
|
418
|
+
const urls = [
|
|
419
|
+
...new Set([imgsrc, imgurl && encodeURI(imgurl), maskurl && encodeURI(maskurl), defaultMask].filter(Boolean)),
|
|
420
|
+
]
|
|
421
|
+
return {
|
|
422
|
+
imgsrc,
|
|
423
|
+
imgurl,
|
|
424
|
+
maskurl,
|
|
425
|
+
background,
|
|
426
|
+
position,
|
|
427
|
+
imgwidth,
|
|
428
|
+
imgheight,
|
|
429
|
+
urls,
|
|
430
|
+
maskAsset: maskurl ? encodeURI(maskurl) : defaultMask,
|
|
431
|
+
key: JSON.stringify([urls, maskurl, defaultMask]),
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
componentDidUpdate() {
|
|
436
|
+
if (this.getButtonAppearance().key !== this._buttonImageKey) this.prepareButtonImage()
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async prepareButtonImage() {
|
|
440
|
+
const appearance = this.getButtonAppearance()
|
|
441
|
+
const version = (this._buttonImageVersion = (this._buttonImageVersion || 0) + 1)
|
|
442
|
+
this._buttonImageKey = appearance.key
|
|
443
|
+
this.readyGate.close()
|
|
444
|
+
const [loaded, mask] = await Promise.all([
|
|
445
|
+
Promise.all(appearance.urls.filter((url) => url !== appearance.maskAsset).map((url) => preloadButtonImage(url))),
|
|
446
|
+
appearance.maskAsset ? prepareButtonMask(appearance.maskAsset) : Promise.resolve(null),
|
|
447
|
+
])
|
|
448
|
+
const stale = () => !this._isMounted || this._buttonImageVersion !== version
|
|
449
|
+
if (stale()) {
|
|
450
|
+
if (mask) URL.revokeObjectURL(mask)
|
|
451
|
+
return
|
|
452
|
+
}
|
|
453
|
+
const fallback = loaded.some((success) => !success) || (!!appearance.maskAsset && !mask)
|
|
454
|
+
const ready = !fallback || (await preloadButtonImage(defaultBubble))
|
|
455
|
+
if (stale()) {
|
|
456
|
+
if (mask) URL.revokeObjectURL(mask)
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
if (this._buttonMaskUrl) URL.revokeObjectURL(this._buttonMaskUrl)
|
|
460
|
+
this._buttonMaskUrl = mask
|
|
461
|
+
this.setState({ready, readyImageKey: appearance.key, fallbackButtonImage: fallback, buttonMaskUrl: mask})
|
|
462
|
+
this.readyGate.open()
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
componentWillUnmount() {
|
|
466
|
+
if (this._buttonMaskUrl) URL.revokeObjectURL(this._buttonMaskUrl)
|
|
467
|
+
if (this._animateTimeout) clearTimeout(this._animateTimeout)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
renderButton() {
|
|
471
|
+
if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_button = sb.Date.now()
|
|
472
|
+
const appearance = this.getButtonAppearance()
|
|
473
|
+
let {imgsrc, imgurl, maskurl, background, position, imgwidth, imgheight} = appearance
|
|
474
|
+
// Never attach a remote CSS mask while the local copy is being prepared.
|
|
475
|
+
if (appearance.maskAsset) {
|
|
476
|
+
maskurl = this.state.readyImageKey === appearance.key ? this.state.buttonMaskUrl : ''
|
|
477
|
+
if (imgsrc === appearance.maskAsset) imgsrc = maskurl || ''
|
|
478
|
+
}
|
|
479
|
+
if (this.state.readyImageKey === appearance.key && this.state.fallbackButtonImage) {
|
|
480
|
+
imgsrc = imgurl = defaultBubble
|
|
481
|
+
maskurl = ''
|
|
482
|
+
}
|
|
483
|
+
|
|
436
484
|
let whitebgcls = 'chat-button--white-bg'
|
|
437
485
|
if (!imgurl && maskurl) whitebgcls += ' chat-button--white-bg--mask-only'
|
|
438
486
|
let imgcontainerstyle = ''
|
|
439
487
|
|
|
440
|
-
imgurl = this.props.store.replaceFileUrl(imgurl)
|
|
441
|
-
imgsrc = this.props.store.replaceFileUrl(imgsrc)
|
|
442
|
-
maskurl = this.props.store.replaceFileUrl(maskurl)
|
|
443
|
-
imgurl = addVersionParam(imgurl)
|
|
444
|
-
imgsrc = addVersionParam(imgsrc)
|
|
445
|
-
maskurl = addVersionParam(maskurl)
|
|
446
|
-
|
|
447
488
|
if (!imgurl && !maskurl) {
|
|
448
489
|
whitebgcls += ' chat-button--white-bg--mask-only'
|
|
449
490
|
imgcontainerstyle = `
|
|
450
|
-
-webkit-mask-image:
|
|
451
|
-
-o-mask-image:
|
|
452
|
-
-moz-mask-image:
|
|
453
|
-
mask-image:
|
|
491
|
+
-webkit-mask-image: none !important;
|
|
492
|
+
-o-mask-image: none !important;
|
|
493
|
+
-moz-mask-image: none !important;
|
|
494
|
+
mask-image: none !important;
|
|
454
495
|
height: ${imgheight}px !important;
|
|
455
496
|
width: ${imgwidth}px !important;
|
|
456
497
|
background: ${background} !important;
|
|
@@ -509,16 +550,22 @@ export default class ChatButton extends Com {
|
|
|
509
550
|
|
|
510
551
|
`
|
|
511
552
|
|
|
512
|
-
if (!this.state.ready) cls += ' hidden'
|
|
553
|
+
if (!this.state.ready || this.state.readyImageKey !== appearance.key) cls += ' hidden'
|
|
513
554
|
|
|
514
555
|
return (
|
|
515
|
-
<
|
|
556
|
+
<button
|
|
557
|
+
type='button'
|
|
558
|
+
class={cls}
|
|
559
|
+
aria-label={this.props.t('chat')}
|
|
560
|
+
aria-expanded={!this.props.isShow}
|
|
561
|
+
onClick={(e) => this.onClick(e)}
|
|
562
|
+
>
|
|
516
563
|
<div class={whitebgcls} style={whiteBgStyle}></div>
|
|
517
564
|
<div class='chat-button--img-container' style={imgcontainerstyle}>
|
|
518
565
|
<img width='70' height='70' alt='chat button' class='chat-button--img' src={imgsrc} />
|
|
519
566
|
</div>
|
|
520
567
|
{this.renderUnread()}
|
|
521
|
-
</
|
|
568
|
+
</button>
|
|
522
569
|
)
|
|
523
570
|
}
|
|
524
571
|
|
|
@@ -551,7 +598,7 @@ export default class ChatButton extends Com {
|
|
|
551
598
|
}
|
|
552
599
|
return defmsg
|
|
553
600
|
}
|
|
554
|
-
return <Block block={block} />
|
|
601
|
+
return <Block block={block} store={this.props.store} t={this.props.t} />
|
|
555
602
|
}
|
|
556
603
|
|
|
557
604
|
let message = sb.get(ev, 'data.message.text', defmsg)
|
|
@@ -600,3 +647,37 @@ function addVersionParam(url, version = 8) {
|
|
|
600
647
|
return hash ? newUrl + '#' + hash : newUrl
|
|
601
648
|
}
|
|
602
649
|
}
|
|
650
|
+
|
|
651
|
+
// Use the exact rendered URL, including its version, for both images and masks.
|
|
652
|
+
function preloadButtonImage(src, {crossOrigin = false} = {}) {
|
|
653
|
+
return new Promise((resolve) => {
|
|
654
|
+
const image = new Image()
|
|
655
|
+
if (crossOrigin) image.crossOrigin = 'anonymous'
|
|
656
|
+
image.onerror = () => resolve(false)
|
|
657
|
+
image.onload = async () => {
|
|
658
|
+
try {
|
|
659
|
+
if (image.decode) await image.decode()
|
|
660
|
+
resolve(true)
|
|
661
|
+
} catch (_) {
|
|
662
|
+
resolve(false)
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
image.src = src
|
|
666
|
+
})
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// CSS masks use a separate CORS image request. Pin the loaded bytes locally so
|
|
670
|
+
// revealing the white backing never races another network request by CSS.
|
|
671
|
+
async function prepareButtonMask(src) {
|
|
672
|
+
let url
|
|
673
|
+
try {
|
|
674
|
+
const response = await fetch(src)
|
|
675
|
+
if (!response.ok) return null
|
|
676
|
+
url = URL.createObjectURL(await response.blob())
|
|
677
|
+
if (await preloadButtonImage(url)) return url
|
|
678
|
+
} catch (_) {
|
|
679
|
+
// Use the bundled fallback if the custom mask cannot be loaded.
|
|
680
|
+
}
|
|
681
|
+
if (url) URL.revokeObjectURL(url)
|
|
682
|
+
return null
|
|
683
|
+
}
|
package/src/chatbox/Event.js
CHANGED
|
@@ -28,11 +28,31 @@ 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
|
+
const ev = this.props.event.ev
|
|
32
|
+
const age = (this.props.store.now ? this.props.store.now() : sb.Date.now()) - ev.created
|
|
33
|
+
// Capture this once: acknowledgement keeps the same component and animation.
|
|
34
|
+
this.animateSend = !props.isHistory && ev.type === 'message_sent' &&
|
|
35
|
+
sb.get(ev, 'by.type') === 'user' && ev.id === sb.get(ev, 'source_event_id') &&
|
|
36
|
+
age >= 0 && age < 2000
|
|
31
37
|
this.textMessageRef = createRef()
|
|
32
38
|
this.fileAttachmentRef = createRef()
|
|
33
39
|
this.imageAttachmentRef = createRef()
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
componentDidMount() {
|
|
43
|
+
if (!this.animateSend) return
|
|
44
|
+
// Paint the starting position before transitioning to the resting position.
|
|
45
|
+
this.sendAnimationFrame = window.requestAnimationFrame(() => {
|
|
46
|
+
this.sendAnimationFrame = window.requestAnimationFrame(() => {
|
|
47
|
+
if (this._isMounted) this.setState({sendEntered: true})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
componentWillUnmount() {
|
|
53
|
+
if (this.sendAnimationFrame) window.cancelAnimationFrame(this.sendAnimationFrame)
|
|
54
|
+
}
|
|
55
|
+
|
|
36
56
|
focusSourceEventFromQuote = (ev) => {
|
|
37
57
|
let $textMessage = this.textMessageRef.current
|
|
38
58
|
if ($textMessage && typeof $textMessage.focusSourceEventFromQuote === 'function') {
|
|
@@ -90,6 +110,7 @@ export default class Event extends Com {
|
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
chooseQuickReply(reply) {
|
|
113
|
+
if (this.props.isHistory) return
|
|
93
114
|
let ev = sb.get(this.props.event, 'ev', {})
|
|
94
115
|
let message = {text: reply.title, format: 'plaintext'}
|
|
95
116
|
if (reply.payload) {
|
|
@@ -107,6 +128,7 @@ export default class Event extends Com {
|
|
|
107
128
|
}
|
|
108
129
|
|
|
109
130
|
choosePostbackBtn(button) {
|
|
131
|
+
if (this.props.isHistory) return
|
|
110
132
|
let ev = sb.get(this.props.event, 'ev', {})
|
|
111
133
|
let message = {text: button.title, format: 'plaintext'}
|
|
112
134
|
if (button.payload) {
|
|
@@ -252,6 +274,14 @@ export default class Event extends Com {
|
|
|
252
274
|
|
|
253
275
|
renderMessageSent() {
|
|
254
276
|
let ev = this.props.event.ev
|
|
277
|
+
if (sb.get(ev, 'data.message.deleted')) {
|
|
278
|
+
let byType = sb.get(ev, 'by.type') === 'user' ? 'user' : 'agent'
|
|
279
|
+
return (
|
|
280
|
+
<div class={'convo-event ' + byType + '-message'} data-ev-id={ev.id}>
|
|
281
|
+
<TextMessage ev={ev} t={this.props.t} store={this.props.store} />
|
|
282
|
+
</div>
|
|
283
|
+
)
|
|
284
|
+
}
|
|
255
285
|
let attachments = sb.get(ev, 'data.message.attachments')
|
|
256
286
|
let hasForm = sb.find(attachments, (att) => att.type === 'form')
|
|
257
287
|
if (sb.isEmptyMessage(sb.get(ev, 'data.message'))) return null
|
|
@@ -312,7 +342,7 @@ export default class Event extends Com {
|
|
|
312
342
|
ev={ev}
|
|
313
343
|
/>
|
|
314
344
|
<OrderAttachments t={this.props.t} store={this.props.store} ev={ev} />
|
|
315
|
-
<QuickReplies store={this.props.store} ev={ev} onSelect={(e) => this.chooseQuickReply(e)} />
|
|
345
|
+
{!this.props.isHistory && <QuickReplies store={this.props.store} ev={ev} onSelect={(e) => this.chooseQuickReply(e)} />}
|
|
316
346
|
{this.renderReactions()}
|
|
317
347
|
{this.renderAIDevNote()}
|
|
318
348
|
</div>
|
|
@@ -321,14 +351,14 @@ export default class Event extends Com {
|
|
|
321
351
|
)
|
|
322
352
|
}
|
|
323
353
|
|
|
324
|
-
if (sb.get(ev, '
|
|
354
|
+
if (sb.get(ev, 'source_event_id') === ev.id && this.props.store.now() - ev.created < 900) {
|
|
325
355
|
sb.setTimeout(() => this.setState({refresh: this.state.refresh}), 1000)
|
|
326
356
|
}
|
|
327
357
|
|
|
328
358
|
// only show sending while the message is send too long (>300ms) but haven't returned from
|
|
329
359
|
// the server
|
|
330
360
|
let $dot = <div class='sending_dot'></div>
|
|
331
|
-
if (this.props.store.now() - ev.created < 900 || sb.get(ev, '
|
|
361
|
+
if (this.props.store.now() - ev.created < 900 || sb.get(ev, 'source_event_id') !== ev.id) {
|
|
332
362
|
$dot = <div class='sending_dot sending_dot__hide'></div>
|
|
333
363
|
}
|
|
334
364
|
|
|
@@ -352,11 +382,12 @@ export default class Event extends Com {
|
|
|
352
382
|
return (
|
|
353
383
|
<div class='convo-event user-message' data-ev-id={ev.id}>
|
|
354
384
|
{$sender}
|
|
355
|
-
<div class='message-user__container'>
|
|
385
|
+
<div class={'message-user__container' + (this.animateSend && !this.props.isHistory ? ' message-user__container--send' + (this.state.sendEntered ? '' : ' message-user__container--enter') : '')}>
|
|
356
386
|
{$dot}
|
|
357
387
|
<TextMessage
|
|
358
388
|
ref={this.textMessageRef}
|
|
359
389
|
store={this.props.store}
|
|
390
|
+
t={this.props.t}
|
|
360
391
|
ev={ev}
|
|
361
392
|
refresh={this.state.refresh}
|
|
362
393
|
onLink={this.props.onLink}
|
|
@@ -376,6 +407,7 @@ export default class Event extends Com {
|
|
|
376
407
|
}
|
|
377
408
|
|
|
378
409
|
async onSendReaction(action) {
|
|
410
|
+
if (this.props.isHistory) return
|
|
379
411
|
if (this._reacting) return
|
|
380
412
|
let ev = this.props.event.ev
|
|
381
413
|
let cid = sb.get(ev, 'data.message.conversation_id')
|
|
@@ -423,6 +455,7 @@ export default class Event extends Com {
|
|
|
423
455
|
}
|
|
424
456
|
|
|
425
457
|
renderReactions() {
|
|
458
|
+
if (this.props.isHistory) return null
|
|
426
459
|
if (this.props.store.isAIDevMode()) return null
|
|
427
460
|
let cid = sb.get(this.props.event.ev, 'data.message.conversation_id', '')
|
|
428
461
|
if (cid.startsWith('cslight')) return null
|
|
@@ -515,7 +548,7 @@ export default class Event extends Com {
|
|
|
515
548
|
let byid = sb.get(ev, 'by.display_id', sb.get(ev, 'by.id')) || ''
|
|
516
549
|
if (bytype === 'user') return sb.getUserDisplayName(this.props.store.matchUser())
|
|
517
550
|
let acc = this.props.store.matchAccount()
|
|
518
|
-
if (bytype === 'agent') return sb.getAgentDisplayName(acc, this.props.store.matchAgent(byid))
|
|
551
|
+
if (bytype === 'agent' || sb.get(ev, 'by.display_type') === 'agent') return sb.getAgentDisplayName(acc, this.props.store.matchAgent(byid))
|
|
519
552
|
if (byid.startsWith('at')) return sb.getAgentDisplayName(acc, this.props.store.matchAgent(byid))
|
|
520
553
|
if (bytype === 'bot') {
|
|
521
554
|
let bot = this.props.store.matchBot()[byid]
|