@subiz/widget-v4 4.0.50 → 4.0.55
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/img/default.jpg +0 -0
- package/assets/less/message.less +101 -10
- package/compiled_src/chatbox/Event.js +6 -0
- package/compiled_src/chatbox/OrderAttachments.js +109 -0
- package/compiled_src/chatbox/ProductAttachments.js +9 -7
- package/compiled_src/notif/notif.js +6 -2
- package/compiled_src/plugin.js +1 -1
- package/compiled_src/store/api.js +1 -0
- package/compiled_src/util/campaign.js +6 -1
- package/compiled_src/util/common.js +7 -0
- package/dist/{17cbc0a3e5f.178.js → 17d7ef81b7a.178.js} +1 -1
- package/dist/{17cbc0a3e5f.213.js → 17d7ef81b7a.213.js} +0 -0
- package/dist/{17cbc0a3e5f.362.js → 17d7ef81b7a.362.js} +1 -1
- package/dist/17d7ef81b7a.441.js +1 -0
- package/dist/17d7ef81b7a.605.js +1 -0
- package/dist/{17cbc0a3e5f.619.js → 17d7ef81b7a.619.js} +1 -1
- package/dist/{17cbc0a3e5f.678.js → 17d7ef81b7a.678.js} +0 -0
- package/dist/17d7ef81b7a.74.js +1 -0
- package/dist/{17cbc0a3e5f.782.js → 17d7ef81b7a.782.js} +1 -1
- package/dist/17d7ef81b7a.app.js +1 -0
- package/dist/{17cbc0a3e5f.index.html → 17d7ef81b7a.index.html} +1 -1
- package/dist/{17cbc0a3e5f.library.html → 17d7ef81b7a.library.html} +1 -1
- package/dist/17d7ef81b7a.library.js +1 -0
- package/dist/{17cbc0a3e5f.preview.html → 17d7ef81b7a.preview.html} +1 -1
- package/dist/17d7ef81b7a.preview.js +1 -0
- package/dist/17d7ef81b7a.screenshoot.js +1 -0
- package/dist/17d7ef84382.178.js +406 -0
- package/dist/17d7ef84382.213.js +3223 -0
- package/dist/17d7ef84382.362.js +107 -0
- package/dist/17d7ef84382.441.js +2706 -0
- package/dist/17d7ef84382.605.js +391 -0
- package/dist/17d7ef84382.619.js +777 -0
- package/dist/17d7ef84382.678.js +107 -0
- package/dist/17d7ef84382.74.js +4732 -0
- package/dist/17d7ef84382.782.js +107 -0
- package/dist/17d7ef84382.screenshoot.js +5719 -0
- package/dist/HASH +1 -1
- package/dist/assets/img/default.06e6ee0.jpg +0 -0
- package/dist/screenshoot.html +7 -0
- package/package.json +12 -12
- package/screenshoot.html +15 -0
- package/screenshoot.js +28 -0
- package/src/chatbox/Event.js +2 -0
- package/src/chatbox/OrderAttachments.js +107 -0
- package/src/chatbox/ProductAttachments.js +14 -8
- package/src/notif/notif.js +36 -27
- package/src/plugin.js +1 -1
- package/src/store/api.js +2 -5
- package/src/store/store.js +9 -8
- package/src/util/campaign.js +14 -11
- package/src/util/common.js +6 -0
- package/take.js +36 -0
- package/webpack.dev.js +7 -0
- package/webpack.prod.js +12 -2
- package/webpack.screenshoot.js +28 -0
- package/dist/17cbc0a3e5f.605.js +0 -1
- package/dist/17cbc0a3e5f.712.js +0 -1
- package/dist/17cbc0a3e5f.84.js +0 -1
- package/dist/17cbc0a3e5f.app.js +0 -1
- package/dist/17cbc0a3e5f.library.js +0 -1
- package/dist/17cbc0a3e5f.preview.js +0 -1
package/dist/HASH
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
17d7ef84382
|
|
Binary file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<html><head><meta name="viewport" content="width=device-width,intial-scale=1"/><style>/* make the environment look like widget environment */
|
|
2
|
+
#sbz-pop * {
|
|
3
|
+
all: unset;
|
|
4
|
+
}
|
|
5
|
+
body {
|
|
6
|
+
background: #ddd;
|
|
7
|
+
}</style></head><body><script defer="defer" src="./17d7ef84382.screenshoot.js"></script></body></html>
|
package/package.json
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subiz/widget-v4",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.55",
|
|
4
4
|
"main": "./compiled_src/lib.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npx webpack serve --config webpack.dev.js",
|
|
7
|
-
"build": "npx webpack --config webpack.prod.js",
|
|
7
|
+
"build": "rm -rf dist && npx webpack --config webpack.prod.js && npx webpack --config webpack.screenshoot.js",
|
|
8
8
|
"report": "npx webpack --config webpack.report.js",
|
|
9
9
|
"lib": "rm -rf compiled_src && npx babel --out-dir=compiled_src src"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@
|
|
13
|
-
"@googlemaps/js-api-loader": "^1.11.4",
|
|
12
|
+
"@googlemaps/js-api-loader": "^1.12.11",
|
|
14
13
|
"@subiz/ajax": "^3.0.12",
|
|
15
14
|
"@subiz/flow": "^1.0.9",
|
|
16
15
|
"@subiz/storage": "0.0.8",
|
|
17
16
|
"@subiz/wsclient": "^3.1.7",
|
|
18
|
-
"babel-loader": "^8.2.3",
|
|
19
17
|
"cookie_js": "1.4.2",
|
|
20
|
-
"core-js": "^3.19.
|
|
18
|
+
"core-js": "^3.19.2",
|
|
21
19
|
"css-loader": "^5.2.6",
|
|
22
20
|
"file-loader": "^6.2.0",
|
|
23
21
|
"less": "^4.1.2",
|
|
24
22
|
"less-loader": "^10.2.0",
|
|
25
|
-
"marked": "^4.0.
|
|
26
|
-
"preact": "^10.
|
|
23
|
+
"marked": "^4.0.6",
|
|
24
|
+
"preact": "^10.6.2"
|
|
27
25
|
},
|
|
28
26
|
"devDependencies": {
|
|
27
|
+
"babel-loader": "^8.2.3",
|
|
28
|
+
"@babel/core": "^7.16.0",
|
|
29
29
|
"@babel/cli": "^7.16.0",
|
|
30
30
|
"@babel/plugin-proposal-class-properties": "^7.16.0",
|
|
31
31
|
"@babel/plugin-transform-react-jsx": "^7.16.0",
|
|
32
|
-
"@babel/preset-env": "^7.16.
|
|
32
|
+
"@babel/preset-env": "^7.16.4",
|
|
33
33
|
"babel-plugin-syntax-jsx": "^6.18.0",
|
|
34
34
|
"html-webpack-plugin": "^5.5.0",
|
|
35
|
-
"
|
|
36
|
-
"webpack": "^5.
|
|
35
|
+
"puppeteer": "^12.0.1",
|
|
36
|
+
"webpack": "^5.64.4",
|
|
37
37
|
"webpack-bundle-analyzer": "^4.5.0",
|
|
38
38
|
"webpack-cli": "^4.9.1",
|
|
39
|
-
"webpack-dev-server": "^4.
|
|
39
|
+
"webpack-dev-server": "^4.6.0"
|
|
40
40
|
}
|
|
41
41
|
}
|
package/screenshoot.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<meta name="viewport" content="width=device-width, intial-scale=1.0" />
|
|
4
|
+
<style>
|
|
5
|
+
/* make the environment look like widget environment */
|
|
6
|
+
#sbz-pop * {
|
|
7
|
+
all: unset;
|
|
8
|
+
}
|
|
9
|
+
body {
|
|
10
|
+
background: #ddd;
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body></body>
|
|
15
|
+
</html>
|
package/screenshoot.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Widget from './src/lib.js'
|
|
2
|
+
|
|
3
|
+
let accid = 'acqsulrowbxiugvginhw'
|
|
4
|
+
let widget = new Widget(
|
|
5
|
+
'https://api.subiz.com.vn/4.0/',
|
|
6
|
+
'https://file-subiz.com/',
|
|
7
|
+
'https://rt-0.subiz.com.vn/',
|
|
8
|
+
true,
|
|
9
|
+
true,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
function main() {
|
|
13
|
+
var $div = document.createElement('div')
|
|
14
|
+
document.body.appendChild($div)
|
|
15
|
+
let hash = document.location.hash.substr(1)
|
|
16
|
+
let plugin = JSON.parse(decodeURIComponent(atob(hash)))
|
|
17
|
+
plugin.triggers = [{type: 'after_pageview', after_pageview_sec: 0, enabled: true}]
|
|
18
|
+
if (plugin.popup) plugin.popup.overlay = false
|
|
19
|
+
plugin._dont_close = true
|
|
20
|
+
plugin._page_index = 0
|
|
21
|
+
|
|
22
|
+
plugin.account_id = accid
|
|
23
|
+
widget._overridePlugin([plugin])
|
|
24
|
+
// widget._overrideDeviceType('mobile')
|
|
25
|
+
widget.setAccount(accid, $div)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
main()
|
package/src/chatbox/Event.js
CHANGED
|
@@ -7,6 +7,7 @@ import FormAttachments from './FormAttachments.js'
|
|
|
7
7
|
import FormSubmitAttachments from './FormSubmitAttachments.js'
|
|
8
8
|
import GenericTemplateAttachments from './GenericTemplateAttachments.js'
|
|
9
9
|
import ProductAttachments from './ProductAttachments.js'
|
|
10
|
+
import OrderAttachments from './OrderAttachments.js'
|
|
10
11
|
//import FormSubmitAttachment from './formSubmitAttachment.js'
|
|
11
12
|
import VideoAttachments from './VideoAttachments.js'
|
|
12
13
|
import TextMessage from './TextMessage.js'
|
|
@@ -140,6 +141,7 @@ export default class Event extends Com {
|
|
|
140
141
|
<FormSubmitAttachments store={this.props.store} ev={ev} t={this.props.t} />
|
|
141
142
|
<GenericTemplateAttachments store={this.props.store} ev={ev} onSelect={(e) => this.choosePostbackBtn(e)} />
|
|
142
143
|
<ProductAttachments t={this.props.t} store={this.props.store} ev={ev} />
|
|
144
|
+
<OrderAttachments t={this.props.t} store={this.props.store} ev={ev} />
|
|
143
145
|
<QuickReplies store={this.props.store} ev={ev} onSelect={(e) => this.chooseQuickReply(e)} />
|
|
144
146
|
</div>
|
|
145
147
|
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import sb from '../util/index.js'
|
|
2
|
+
import {Com} from '../common.js'
|
|
3
|
+
import {h, createRef, Fragment} from 'preact'
|
|
4
|
+
|
|
5
|
+
export default class ProductAttachments extends Com {
|
|
6
|
+
render() {
|
|
7
|
+
let byType = sb.get(this.props.ev, 'by.type')
|
|
8
|
+
if (byType === 'user') return null
|
|
9
|
+
// filter out all generic
|
|
10
|
+
|
|
11
|
+
let acc = this.props.store.matchAccount()
|
|
12
|
+
var attachments = sb.get(this.props.ev, 'data.message.attachments', [])
|
|
13
|
+
let orders = sb.filter(attachments, (att) => att.type === 'order' && att.order).map((att) => att.order)
|
|
14
|
+
|
|
15
|
+
if (orders.length === 0) return null
|
|
16
|
+
|
|
17
|
+
let $orders = sb.map(orders, (order, index) => {
|
|
18
|
+
let $note = null
|
|
19
|
+
if (order.note) {
|
|
20
|
+
$note = (
|
|
21
|
+
<div>
|
|
22
|
+
<div class='order_attachment__label'>{this.props.t('note')}</div>
|
|
23
|
+
<div class='order_attachment__text_truncate'>{order.note}</div>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let $products = null
|
|
29
|
+
if (sb.size(order.items) > 0) {
|
|
30
|
+
$products = (
|
|
31
|
+
<div>
|
|
32
|
+
<div class='order_attachment__label'>{this.props.t('product')}</div>
|
|
33
|
+
{sb.map(order.items, (item) => {
|
|
34
|
+
let product = item.product || {}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div class='order_attachment__product'>
|
|
38
|
+
<img
|
|
39
|
+
class='order_attachment__product_img'
|
|
40
|
+
src={(sb.get(product, 'images.0'), require('../../assets/img/default.jpg'))}
|
|
41
|
+
/>
|
|
42
|
+
<div style='overflow: hidden !important;'>
|
|
43
|
+
<div class='order_attachment__product_name'>{product.name}</div>
|
|
44
|
+
<div class='order_attachment__product_desc'>{product.description || product.long_description}</div>
|
|
45
|
+
<div class='order_attachment__product_desc'>
|
|
46
|
+
{this.props.t('qty')} {item.quantity} · {sb.formatCurrency(product.price)}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
})}
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let $total = (
|
|
57
|
+
<div class='order_attachment__footer'>
|
|
58
|
+
<div>{this.props.t('total')}</div>{' '}
|
|
59
|
+
<div>
|
|
60
|
+
<b>{sb.formatCurrency(order.total)}</b>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
let addr = sb.get(order, 'shipping.address', {})
|
|
66
|
+
let fulladdr = [addr.street, addr.ward, addr.district, addr.region, addr.country].filter((a) => a).join(', ')
|
|
67
|
+
let address = fulladdr
|
|
68
|
+
|
|
69
|
+
let phoneattr = sb.find(sb.get(order, 'user.attributes', []), (attr) => attr.key === 'phones') || {
|
|
70
|
+
key: 'phones',
|
|
71
|
+
text: '',
|
|
72
|
+
}
|
|
73
|
+
let phone = sb.get(order, 'shipping.address.phone', '').trim()
|
|
74
|
+
phone = phone || sb.trim(phoneattr.text)
|
|
75
|
+
if (phone) phone = this.props.t('phn') + ': ' + phone
|
|
76
|
+
|
|
77
|
+
let $shipto = null
|
|
78
|
+
if (address || phone) {
|
|
79
|
+
$shipto = (
|
|
80
|
+
<div>
|
|
81
|
+
<div class='order_attachment__label'>{this.props.t('ship_to')}</div>
|
|
82
|
+
<div class='order_attachment__text_truncate'>{address}</div>
|
|
83
|
+
<div class='order_attachment__text_truncate'>{phone}</div>
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div class={`order_attachment order_attachment__${byType}`}>
|
|
90
|
+
<div class='order_attachment__header'>
|
|
91
|
+
{this.props.t('order')}
|
|
92
|
+
<span class='order_attachment__text_muted order_attachment__text_sm'>#{order.id}</span>
|
|
93
|
+
</div>
|
|
94
|
+
{$products}
|
|
95
|
+
{$shipto}
|
|
96
|
+
<div>
|
|
97
|
+
<div class='order_attachment__label'>{this.props.t('payment')}</div>
|
|
98
|
+
<div>COD</div>
|
|
99
|
+
</div>
|
|
100
|
+
{$note}
|
|
101
|
+
{$total}
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
return $orders
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -16,6 +16,9 @@ export default class ProductAttachments extends Com {
|
|
|
16
16
|
products = products.filter((product) => product.product && product.product.name)
|
|
17
17
|
|
|
18
18
|
if (products.length === 0) return null
|
|
19
|
+
|
|
20
|
+
let acc = this.props.store.matchAccount()
|
|
21
|
+
|
|
19
22
|
let $products = sb.map(products, (att, index) => {
|
|
20
23
|
let product = att.product
|
|
21
24
|
|
|
@@ -32,23 +35,26 @@ export default class ProductAttachments extends Com {
|
|
|
32
35
|
|
|
33
36
|
let $title = (
|
|
34
37
|
<a href={url} class='product_attachment__title' target='_blank'>
|
|
35
|
-
{
|
|
38
|
+
{product.name}
|
|
36
39
|
</a>
|
|
37
40
|
)
|
|
38
41
|
let $subtitle = null
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
let desc = product.description || product.long_description
|
|
43
|
+
if (desc) $subtitle = <div class='product_attachment__subtitle'>{desc}</div>
|
|
41
44
|
|
|
42
45
|
let $price = null
|
|
43
|
-
if (product.
|
|
44
|
-
$price =
|
|
46
|
+
if (product.price) {
|
|
47
|
+
$price = (
|
|
48
|
+
<div class='product_attachment__price'>
|
|
49
|
+
{product.currency || sb.get(acc, 'currency', '')} {sb.formatCurrency(product.price)}
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
45
52
|
}
|
|
46
|
-
|
|
47
53
|
return (
|
|
48
54
|
<div class={'product_attachment product_attachment__' + byType}>
|
|
49
55
|
<div>
|
|
50
|
-
<a href={this.props.store.replaceFileUrl(product.
|
|
51
|
-
<img class='product_attachment__img' src={this.props.store.replaceFileUrl(product.
|
|
56
|
+
<a href={this.props.store.replaceFileUrl(product.image)} target='_blank'>
|
|
57
|
+
<img class='product_attachment__img' src={this.props.store.replaceFileUrl(product.image)} />
|
|
52
58
|
</a>
|
|
53
59
|
</div>
|
|
54
60
|
{$title}
|
package/src/notif/notif.js
CHANGED
|
@@ -68,17 +68,17 @@ export default class Notif extends Com {
|
|
|
68
68
|
|
|
69
69
|
renderCloseButton() {
|
|
70
70
|
return (
|
|
71
|
-
<div class=
|
|
71
|
+
<div class='btn_close' onClick={(e) => this.onCloseButtonClick(e)}>
|
|
72
72
|
<svg
|
|
73
|
-
class=
|
|
74
|
-
xmlns=
|
|
75
|
-
width=
|
|
76
|
-
height=
|
|
77
|
-
viewBox=
|
|
78
|
-
stroke-linecap=
|
|
79
|
-
stroke-linejoin=
|
|
80
|
-
<line x1=
|
|
81
|
-
<line x1=
|
|
73
|
+
class='btn_close__icon'
|
|
74
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
75
|
+
width='24'
|
|
76
|
+
height='24'
|
|
77
|
+
viewBox='0 0 24 24'
|
|
78
|
+
stroke-linecap='round'
|
|
79
|
+
stroke-linejoin='round'>
|
|
80
|
+
<line x1='18' y1='6' x2='6' y2='18' style='stroke-width: 3 !important;'></line>
|
|
81
|
+
<line x1='6' y1='6' x2='18' y2='18' style='stroke-width: 3 !important;'></line>
|
|
82
82
|
</svg>
|
|
83
83
|
</div>
|
|
84
84
|
)
|
|
@@ -106,7 +106,7 @@ export default class Notif extends Com {
|
|
|
106
106
|
await sb.preloadImg(user.avatar_url)
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
sb.map(sb.get(this.props.plugin, 'notification.custom_avatar_urls'), url => {
|
|
109
|
+
sb.map(sb.get(this.props.plugin, 'notification.custom_avatar_urls'), (url) => {
|
|
110
110
|
profiles.push({
|
|
111
111
|
type: 'person',
|
|
112
112
|
fullname: randomName(),
|
|
@@ -119,7 +119,12 @@ export default class Notif extends Com {
|
|
|
119
119
|
})
|
|
120
120
|
|
|
121
121
|
let i18n_messages = sb.get(this.props, 'plugin.notification.i18n_message_quill_deltas', [])
|
|
122
|
+
|
|
122
123
|
let i18n_message = i18n_messages[Math.floor(Math.random() * sb.size(i18n_messages))]
|
|
124
|
+
|
|
125
|
+
let fallbackmsgs = sb.get(this.props, 'plugin.notification.message_quill_deltas', [])
|
|
126
|
+
let fallbackmessage = fallbackmsgs[Math.floor(Math.random() * sb.size(fallbackmsgs))]
|
|
127
|
+
|
|
123
128
|
let i18n_title = sb.get(this.props, 'plugin.notification.i18n_title_quill_delta')
|
|
124
129
|
|
|
125
130
|
return this.setState({
|
|
@@ -127,8 +132,8 @@ export default class Notif extends Com {
|
|
|
127
132
|
last_show: sb.Date.now(),
|
|
128
133
|
timestamp: timestamp,
|
|
129
134
|
user: user,
|
|
130
|
-
title: this.props.t.i18n(i18n_title),
|
|
131
|
-
message: this.props.t.i18n(i18n_message),
|
|
135
|
+
title: this.props.t.i18n(i18n_title) || sb.get(this.props, 'plugin.notification.title_quill_delta'),
|
|
136
|
+
message: this.props.t.i18n(i18n_message) || fallbackmessage,
|
|
132
137
|
})
|
|
133
138
|
}
|
|
134
139
|
this.setState({closeAnimation: true})
|
|
@@ -140,7 +145,7 @@ export default class Notif extends Com {
|
|
|
140
145
|
async refreshCSS() {
|
|
141
146
|
// make sure you are still alive
|
|
142
147
|
let plugins = this.props.store.matchPlugin()
|
|
143
|
-
let found = sb.find(plugins, plugin => plugin.id === this.props.plugin.id)
|
|
148
|
+
let found = sb.find(plugins, (plugin) => plugin.id === this.props.plugin.id)
|
|
144
149
|
if (!found) return
|
|
145
150
|
let css = (await notifCSS).default.default.toString()
|
|
146
151
|
// var outcss = sb.replaceCssVariablePlugin(css, this.props.plugin.popup)
|
|
@@ -191,7 +196,7 @@ export default class Notif extends Com {
|
|
|
191
196
|
renderTextFromQuillDelta(quilldelta, profile) {
|
|
192
197
|
let qd = sb.parseJSON(quilldelta)
|
|
193
198
|
if (!qd || !qd.ops) return null
|
|
194
|
-
return sb.map(qd.ops, op => {
|
|
199
|
+
return sb.map(qd.ops, (op) => {
|
|
195
200
|
let out = null
|
|
196
201
|
if (!op.insert) return null
|
|
197
202
|
|
|
@@ -215,7 +220,6 @@ export default class Notif extends Com {
|
|
|
215
220
|
if (!this.state.imageReady) return null
|
|
216
221
|
if (this.state.close) return null
|
|
217
222
|
if (!this.state.message) return null
|
|
218
|
-
|
|
219
223
|
let notif = sb.get(this.props.plugin, 'notification', {})
|
|
220
224
|
if (!notif) return null
|
|
221
225
|
let animation = ''
|
|
@@ -244,24 +248,29 @@ export default class Notif extends Com {
|
|
|
244
248
|
return (
|
|
245
249
|
<div
|
|
246
250
|
class={animation + ' notif' + ' notif__' + pos}
|
|
247
|
-
onClick={e => this.onClick(e)}
|
|
248
|
-
onmouseover={e => this.setOver(true)}
|
|
251
|
+
onClick={(e) => this.onClick(e)}
|
|
252
|
+
onmouseover={(e) => this.setOver(true)}
|
|
249
253
|
style={st}
|
|
250
|
-
onmouseleave={e => this.setOver(false)}>
|
|
251
|
-
<div style=
|
|
252
|
-
<img
|
|
254
|
+
onmouseleave={(e) => this.setOver(false)}>
|
|
255
|
+
<div style='position: relative !important; display: flex !important; align-items: center !important;'>
|
|
256
|
+
<img
|
|
257
|
+
alt='notification background'
|
|
258
|
+
class='notif_bg'
|
|
259
|
+
src={notif.background_url}
|
|
260
|
+
style={sb.js2css(notif.background_style)}
|
|
261
|
+
/>
|
|
253
262
|
{this.renderCloseButton()}
|
|
254
|
-
<div class=
|
|
255
|
-
<img alt=
|
|
263
|
+
<div class='notif_avatar' style={sb.js2css(notif.avatar_style)}>
|
|
264
|
+
<img alt='notification avatar' class='notif_avatar__img' src={user.avatar_url} />
|
|
256
265
|
</div>
|
|
257
|
-
<div class=
|
|
258
|
-
<div class=
|
|
266
|
+
<div class='notif_body'>
|
|
267
|
+
<div class='notif_title' style={sb.js2css(notif.title_style)}>
|
|
259
268
|
{this.renderTextFromQuillDelta(this.state.title, user)}
|
|
260
269
|
</div>
|
|
261
|
-
<div class=
|
|
270
|
+
<div class='notif_message' style={sb.js2css(notif.message_style)}>
|
|
262
271
|
{this.renderTextFromQuillDelta(this.state.message, user)}
|
|
263
272
|
</div>
|
|
264
|
-
<div class=
|
|
273
|
+
<div class='notif_time' style={sb.js2css(notif.subtext_style)}>
|
|
265
274
|
{this.state.timestamp}
|
|
266
275
|
</div>
|
|
267
276
|
</div>
|
package/src/plugin.js
CHANGED
|
@@ -372,7 +372,7 @@ function downloadLanguage(store, locale, force) {
|
|
|
372
372
|
const getLocale = (plugin, loc) => {
|
|
373
373
|
if (!loc) loc = ''
|
|
374
374
|
let found = sb.find(plugin.locales, (l) => l.toLowerCase().trim() === loc.toLowerCase().trim())
|
|
375
|
-
if (found) return
|
|
375
|
+
if (found) return found
|
|
376
376
|
|
|
377
377
|
found = sb.find(plugin.locales, (l) => {
|
|
378
378
|
l = l.replace('-', '_').split('_')[0].trim().toLowerCase()
|
package/src/store/api.js
CHANGED
|
@@ -47,10 +47,7 @@ export default class {
|
|
|
47
47
|
.get('/conversations')
|
|
48
48
|
|
|
49
49
|
listMessages = (cid, limit, start_id) =>
|
|
50
|
-
this.apireq
|
|
51
|
-
.addQuery('limit', limit)
|
|
52
|
-
.addQuery('start_id', start_id)
|
|
53
|
-
.get(`/conversations/${cid}/messages`)
|
|
50
|
+
this.apireq.addQuery('limit', limit).addQuery('start_id', start_id).get(`/conversations/${cid}/messages`)
|
|
54
51
|
|
|
55
52
|
ajax = ajax
|
|
56
53
|
|
|
@@ -85,7 +82,7 @@ export default class {
|
|
|
85
82
|
return this.sendEvent({
|
|
86
83
|
by: {id: this.uid, device: device},
|
|
87
84
|
type: 'content_viewed',
|
|
88
|
-
data: {product: {url: pageUrl, title: pageTitle}},
|
|
85
|
+
data: {product: {url: pageUrl, name: pageTitle, title: pageTitle}},
|
|
89
86
|
})
|
|
90
87
|
}
|
|
91
88
|
|
package/src/store/store.js
CHANGED
|
@@ -149,7 +149,7 @@ export default class Store {
|
|
|
149
149
|
overridePlugin(plugins) {
|
|
150
150
|
if (!Array.isArray(plugins)) throw 'plugins must be be an array'
|
|
151
151
|
let pluginM = {}
|
|
152
|
-
sb.map(plugins, function(plugin) {
|
|
152
|
+
sb.map(plugins, function (plugin) {
|
|
153
153
|
pluginM[plugin.id] = plugin
|
|
154
154
|
})
|
|
155
155
|
this.forcePlugins = pluginM
|
|
@@ -1042,7 +1042,7 @@ function getGaClientId() {
|
|
|
1042
1042
|
if (!hasGA()) return clientId
|
|
1043
1043
|
|
|
1044
1044
|
var allTrackers = window.ga.getAll() || []
|
|
1045
|
-
allTrackers.forEach(function(tracker) {
|
|
1045
|
+
allTrackers.forEach(function (tracker) {
|
|
1046
1046
|
clientId = tracker.get('clientId')
|
|
1047
1047
|
})
|
|
1048
1048
|
|
|
@@ -1059,7 +1059,7 @@ function getGaTrackingIds() {
|
|
|
1059
1059
|
if (!hasGA()) return trackingIds
|
|
1060
1060
|
|
|
1061
1061
|
const allTrackers = window.ga.getAll() || []
|
|
1062
|
-
allTrackers.forEach(function(tracker) {
|
|
1062
|
+
allTrackers.forEach(function (tracker) {
|
|
1063
1063
|
var trackingId = tracker.get('trackingId')
|
|
1064
1064
|
if (trackingId) trackingIds.push(trackingId)
|
|
1065
1065
|
})
|
|
@@ -1077,7 +1077,7 @@ function sendToGA(category, action, label) {
|
|
|
1077
1077
|
if (!hasGA()) return
|
|
1078
1078
|
|
|
1079
1079
|
const allTrackers = window.ga.getAll() || []
|
|
1080
|
-
allTrackers.forEach(function(tracker) {
|
|
1080
|
+
allTrackers.forEach(function (tracker) {
|
|
1081
1081
|
const name = tracker.get('name')
|
|
1082
1082
|
window.ga(name + '.send', 'event', category, action, label)
|
|
1083
1083
|
})
|
|
@@ -1090,7 +1090,7 @@ function sendEventToThirdParty(category, action, label) {
|
|
|
1090
1090
|
}
|
|
1091
1091
|
|
|
1092
1092
|
// from http://detectmobilebrowsers.com/
|
|
1093
|
-
let mobileCheck = (function(a) {
|
|
1093
|
+
let mobileCheck = (function (a) {
|
|
1094
1094
|
return (
|
|
1095
1095
|
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
|
|
1096
1096
|
a,
|
|
@@ -1101,6 +1101,7 @@ let mobileCheck = (function(a) {
|
|
|
1101
1101
|
)
|
|
1102
1102
|
})(navigator.userAgent || navigator.vendor || window.opera)
|
|
1103
1103
|
|
|
1104
|
-
let tabletCheck =
|
|
1105
|
-
|
|
1106
|
-
|
|
1104
|
+
let tabletCheck =
|
|
1105
|
+
/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(
|
|
1106
|
+
navigator.userAgent,
|
|
1107
|
+
)
|
package/src/util/campaign.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var common = require('./common.js')
|
|
2
2
|
|
|
3
3
|
// callback when user is about to leave site
|
|
4
|
-
export function trackExitIntent
|
|
5
|
-
let handler = e => {
|
|
4
|
+
export function trackExitIntent(cb) {
|
|
5
|
+
let handler = (e) => {
|
|
6
6
|
if (e.clientY > 10) return // not move to top
|
|
7
7
|
if (cb) cb()
|
|
8
8
|
document.removeEventListener('mouseout', handler)
|
|
@@ -11,8 +11,8 @@ export function trackExitIntent (cb) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// callback after user has scrolled X% down on the current page
|
|
14
|
-
export function trackScrollingPercentage
|
|
15
|
-
let handleScroll = e => {
|
|
14
|
+
export function trackScrollingPercentage(percent, cb) {
|
|
15
|
+
let handleScroll = (e) => {
|
|
16
16
|
let scrollTop = e.srcElement.scrollingElement ? e.srcElement.scrollingElement.scrollTop : e.srcElement.scrollTop
|
|
17
17
|
let scrollHeight = e.srcElement.scrollingElement
|
|
18
18
|
? e.srcElement.scrollingElement.scrollHeight
|
|
@@ -28,14 +28,17 @@ export function trackScrollingPercentage (percent, cb) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// callback when user clicks on a specific part of page
|
|
31
|
-
export function trackAreaClicked
|
|
31
|
+
export function trackAreaClicked(selector, cb) {
|
|
32
32
|
if (!selector) return
|
|
33
33
|
selector = selector || ''
|
|
34
|
-
common.map(selector.split('\n'), selector => {
|
|
34
|
+
common.map(selector.split('\n'), (selector) => {
|
|
35
35
|
selector = common.trim(selector)
|
|
36
36
|
if (!selector) return
|
|
37
|
-
let doms =
|
|
38
|
-
|
|
37
|
+
let doms = []
|
|
38
|
+
try {
|
|
39
|
+
doms = document.querySelectorAll(selector)
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
common.map(doms, (dom) => {
|
|
39
42
|
if (!dom) return
|
|
40
43
|
dom.addEventListener('click', cb, false)
|
|
41
44
|
})
|
|
@@ -43,7 +46,7 @@ export function trackAreaClicked (selector, cb) {
|
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
// callback when user has stopped all activity (clicking, scrolling, ...)
|
|
46
|
-
export function trackInactivity
|
|
49
|
+
export function trackInactivity(seconds, cb) {
|
|
47
50
|
let events = [
|
|
48
51
|
'scroll',
|
|
49
52
|
'keyup',
|
|
@@ -80,9 +83,9 @@ let timeOnPage = 0 // seconds
|
|
|
80
83
|
setInterval(() => timeOnPage++, 1000)
|
|
81
84
|
|
|
82
85
|
// when user has been on the page for at least X seconds
|
|
83
|
-
export function trackTimeOnPage
|
|
86
|
+
export function trackTimeOnPage(seconds, cb) {
|
|
84
87
|
if (seconds < 1) {
|
|
85
|
-
return setTimeout(function
|
|
88
|
+
return setTimeout(function() {
|
|
86
89
|
cb(seconds)
|
|
87
90
|
}, 100)
|
|
88
91
|
}
|
package/src/util/common.js
CHANGED
|
@@ -1071,6 +1071,12 @@ export function getUrlParameter() {
|
|
|
1071
1071
|
|
|
1072
1072
|
export var sleep = (ms) => new Promise((res) => setTimeout(res, ms))
|
|
1073
1073
|
|
|
1074
|
+
export function formatCurrency(val) {
|
|
1075
|
+
if (!val) return 0
|
|
1076
|
+
val = Math.round(val)
|
|
1077
|
+
return val.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1074
1080
|
function replaceFileUrl(src) {
|
|
1075
1081
|
let fileurl = 'https://vcdn.subiz-cdn.com/file/'
|
|
1076
1082
|
if (!src) return ''
|
package/take.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const puppeteer = require('puppeteer')
|
|
2
|
+
|
|
3
|
+
async function take() {
|
|
4
|
+
const browser = await puppeteer.launch({args: ['--no-sandbox']})
|
|
5
|
+
const page = await browser.newPage()
|
|
6
|
+
let templateBase64 = Buffer.from(encodeURIComponent(process.argv[2])).toString('base64')
|
|
7
|
+
|
|
8
|
+
await page.setViewport({width: 940, height: 700})
|
|
9
|
+
await page.goto('file://' + __dirname + '/dist/screenshoot.html#' + templateBase64, {
|
|
10
|
+
waitUntil: 'networkidle2',
|
|
11
|
+
})
|
|
12
|
+
await timeout(3000)
|
|
13
|
+
let out = makeid(20) + '.jpg'
|
|
14
|
+
await page.screenshot({path: out})
|
|
15
|
+
console.log(out)
|
|
16
|
+
browser.close()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function timeout(ms) {
|
|
20
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function makeid(length) {
|
|
24
|
+
var result = []
|
|
25
|
+
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
26
|
+
var charactersLength = characters.length
|
|
27
|
+
for (var i = 0; i < length; i++) {
|
|
28
|
+
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)))
|
|
29
|
+
}
|
|
30
|
+
return result.join('')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
take()
|
|
34
|
+
|
|
35
|
+
// try (remember to run 'npm run build' before running following command)
|
|
36
|
+
// node take.js '{"account_id":"acpxkgumifuoofoosble","id":"cpqzpnooosdhodmkjlixs","name":"Đặt hàng trước","type":"notification","created":1620813049308,"created_by":"agqmwfyuehpuzpehmv","updated":1620816899738,"updated_by":"agqmwfyuehpuzpehmv","triggers":[{"type":"after_pageview"}],"initiative_frequency":{"once_per_session":true},"notification":{"profile_tags":["nam thanh niên","nữ thanh niên"],"profiles":[{"avatar_url":"https://public-gcs.subiz-cdn.com/widget_assets/profile_images/VNM02.png","fullname":"Đoàn Hải Nam","country":"vn","gender":"Male","age":26,"tags":["nam thanh niên","vui tươi"],"email":"hainamxx@gmail.com","phone":"0823588xxx","address":"Hàng Da, Hoàn Kiếm, Hà Nội"},{"avatar_url":"https://public-gcs.subiz-cdn.com/widget_assets/profile_images/VNF03.png","fullname":"Nguyễn Hoàng Lan","country":"vn","gender":"Female","age":36,"tags":["nữ trung niên","lịch sự","vui tươi"],"email":"lannhoanggxx@gmail.com","phone":"0326789xxx","address":"Lũng Cú, Đồng Văn, Hà Giang"},{"avatar_url":"https://public-gcs.subiz-cdn.com/widget_assets/profile_images/VNM04.png","fullname":"Nguyễn Quý Tiến","country":"vn","gender":"Male","age":40,"tags":["nam trung niên","lịch sự"],"email":"tiendzxxx@gmail.com","phone":"056189xxxx","address":"Thụy Khuê, Tây Hồ, Hà Nội"},{"avatar_url":"https://public-gcs.subiz-cdn.com/widget_assets/profile_images/VNF05.png","fullname":"Phạm Hồng Thắm","country":"vn","gender":"Female","age":36,"tags":["nữ trung niên","lịch sự"],"email":"thampham1506xxx@gmail.com","phone":"033820xxxx","address":"Ngọc Đào, Hà Quang, Cao Bằng"},{"avatar_url":"https://public-gcs.subiz-cdn.com/widget_assets/profile_images/VNF06.png","fullname":"Ngô Thị Như Hòa","country":"vn","gender":"Female","age":29,"tags":["nữ thanh niên","lịch sự"],"email":"alice29xxx@gmail.com","phone":"058104xxxx","address":"Xuân Đỉnh, Bắc Từ Liêm, Hà Nội"}],"title_quill_delta":"{\"ops\":[{\"insert\":{\"dynamicField\":{\"id\":\"hesivydbbhoybwyk\",\"value\":\"Họ tên\",\"key\":\"user.fullname\"}}},{\"insert\":\" Ba \\n\"}]}","title_style":{"color":"rgba(255,255,255,1)"},"message_quill_deltas":["{\"ops\":[{\"insert\":\"Đặt trước Note 20 thành công\\n\"}]}"],"message_style":{"color":"rgba(216,207,207,1)"},"url":"https://subiz.com.vn","new_tab":true,"background_url":"https://public-gcs.subiz-cdn.com/widget_assets/notification_background/Frame%20129.png","subtext_style":{},"avatar_style":{"border_radius":"50%"},"position":"bottom-left","interval_sec":60000},"conversion_notification":{"all_agents":true},"template_title":"Đặt hàng trước","thumbnail_url":"https://file-subiz.com/fiqzpohaoyckhgxylulxcpqzpnooosdhodmkjlixs.jpg"}'
|
package/webpack.dev.js
CHANGED
|
@@ -7,6 +7,7 @@ module.exports = {
|
|
|
7
7
|
inject: './inject.js',
|
|
8
8
|
preview: './preview.js',
|
|
9
9
|
library: './library.js',
|
|
10
|
+
screenshoot: './screenshoot.js',
|
|
10
11
|
},
|
|
11
12
|
output: {publicPath: '/'},
|
|
12
13
|
devServer: {port: 8082, host: '0.0.0.0', hot: false, liveReload: false},
|
|
@@ -16,6 +17,12 @@ module.exports = {
|
|
|
16
17
|
new HtmlWebpackPlugin({filename: './preview.html', template: './preview.html', chunks: ['preview']}),
|
|
17
18
|
new HtmlWebpackPlugin({filename: './inject.html', template: './inject.html', inject: 'body', chunks: ['inject']}),
|
|
18
19
|
new HtmlWebpackPlugin({filename: './library.html', template: './index.html', inject: 'body', chunks: ['library']}),
|
|
20
|
+
new HtmlWebpackPlugin({
|
|
21
|
+
filename: './screenshoot.html',
|
|
22
|
+
template: './screenshoot.html',
|
|
23
|
+
inject: 'body',
|
|
24
|
+
chunks: ['screenshoot'],
|
|
25
|
+
}),
|
|
19
26
|
],
|
|
20
27
|
module: {
|
|
21
28
|
rules: [
|