@subiz/widget-v4 4.0.61 → 4.0.66

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 (134) hide show
  1. package/assets/img/caret.svg +1 -0
  2. package/assets/img/done_green.svg +4 -0
  3. package/assets/img/empty_1.svg +11 -0
  4. package/assets/img/ghn.svg +17 -0
  5. package/assets/img/ghtk.svg +18 -0
  6. package/assets/img/home.svg +1 -0
  7. package/assets/img/info.svg +1 -0
  8. package/assets/img/loader.svg +1 -0
  9. package/assets/img/map-pin.svg +1 -0
  10. package/assets/img/not_found_search.png +0 -0
  11. package/assets/img/package.svg +5 -0
  12. package/assets/img/package_fade.svg +1 -0
  13. package/assets/img/phone.svg +1 -0
  14. package/assets/img/search.svg +1 -0
  15. package/assets/img/shop.svg +1 -0
  16. package/assets/img/shop_faded.svg +1 -0
  17. package/assets/img/user.svg +1 -0
  18. package/assets/img/x.svg +5 -0
  19. package/assets/less/chatbox.less +39 -1
  20. package/assets/less/dropdown_select.less +130 -0
  21. package/assets/less/form.less +7 -20
  22. package/assets/less/order.less +489 -0
  23. package/assets/less/rating.less +3 -8
  24. package/babel.config.js +2 -4
  25. package/compiled_src/bot.js +7 -1
  26. package/compiled_src/chatbox/ChatButton.js +3 -1
  27. package/compiled_src/chatbox/DropdownSelect.js +248 -0
  28. package/compiled_src/chatbox/Event.js +5 -2
  29. package/compiled_src/chatbox/Events.js +1 -0
  30. package/compiled_src/chatbox/Order.js +285 -0
  31. package/compiled_src/chatbox/OrderAttachments.js +2 -1
  32. package/compiled_src/chatbox/ProductAttachments.js +40 -4
  33. package/compiled_src/chatbox/TextMessage.js +9 -2
  34. package/compiled_src/chatbox/Typing.js +3 -1
  35. package/compiled_src/chatbox/Widget.js +44 -3
  36. package/compiled_src/chatbox/main.js +2 -0
  37. package/compiled_src/chatbox/spinner.js +1 -1
  38. package/compiled_src/chatbox/time.js +3 -1
  39. package/compiled_src/common.js +40 -1
  40. package/compiled_src/contact/contact.js +1 -3
  41. package/compiled_src/order/address_picker.js +249 -0
  42. package/compiled_src/order/icon.js +62 -0
  43. package/compiled_src/order/index.js +113 -0
  44. package/compiled_src/order/order.js +1234 -0
  45. package/compiled_src/plugin.js +9 -42
  46. package/compiled_src/store/api.js +20 -0
  47. package/compiled_src/store/store.js +67 -3
  48. package/compiled_src/util/common.js +36 -2
  49. package/dist/{74.js → 132.js} +2355 -271
  50. package/dist/178.js +1 -1
  51. package/dist/17fdfed03d1.132.js +1 -0
  52. package/dist/17fdfed03d1.178.js +1 -0
  53. package/dist/17fdfed03d1.213.js +1 -0
  54. package/dist/17fdfed03d1.335.js +1 -0
  55. package/dist/17fdfed03d1.362.js +1 -0
  56. package/dist/17fdfed03d1.441.js +1 -0
  57. package/dist/17fdfed03d1.605.js +1 -0
  58. package/dist/{17db8166252.678.js → 17fdfed03d1.678.js} +0 -0
  59. package/dist/17fdfed03d1.782.js +1 -0
  60. package/dist/17fdfed03d1.app.js +1 -0
  61. package/dist/{17db8166252.index.html → 17fdfed03d1.index.html} +1 -1
  62. package/dist/{17db8166252.library.html → 17fdfed03d1.library.html} +1 -1
  63. package/dist/17fdfed03d1.library.js +1 -0
  64. package/dist/{17db8166252.preview.html → 17fdfed03d1.preview.html} +1 -1
  65. package/dist/17fdfed03d1.preview.js +1 -0
  66. package/dist/17fdfed03d1.screenshoot.js +1 -0
  67. package/dist/213.js +5 -69
  68. package/dist/335.js +411 -0
  69. package/dist/362.js +1 -1
  70. package/dist/441.js +70 -44
  71. package/dist/605.js +1 -64
  72. package/dist/782.js +1 -1
  73. package/dist/HASH +1 -1
  74. package/dist/assets/img/caret.998eb8f.svg +1 -0
  75. package/dist/assets/img/done_green.b817fd4.svg +4 -0
  76. package/dist/assets/img/empty_1.0b98af0.svg +11 -0
  77. package/dist/assets/img/ghn.070f8e3.svg +17 -0
  78. package/dist/assets/img/ghtk.326eac1.svg +18 -0
  79. package/dist/assets/img/info.ebce7ea.svg +1 -0
  80. package/dist/assets/img/loader.37000a7.svg +1 -0
  81. package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
  82. package/dist/assets/img/package.8d37d0f.svg +5 -0
  83. package/dist/assets/img/package_fade.763c001.svg +1 -0
  84. package/dist/assets/img/search.f9705ff.svg +1 -0
  85. package/dist/assets/img/shop.f7dc7d8.svg +1 -0
  86. package/dist/assets/img/shop_faded.df7845a.svg +1 -0
  87. package/dist/assets/img/x.26fdfa3.svg +5 -0
  88. package/dist/screenshoot.html +1 -1
  89. package/dist/screenshoot.js +281 -98
  90. package/order.html +19 -771
  91. package/package.json +15 -16
  92. package/src/bot.js +2 -1
  93. package/src/chatbox/Buttons.js +8 -8
  94. package/src/chatbox/ChatButton.js +2 -2
  95. package/src/chatbox/DropdownSelect.js +229 -0
  96. package/src/chatbox/Event.js +3 -3
  97. package/src/chatbox/Events.js +43 -42
  98. package/src/chatbox/Order.js +232 -0
  99. package/src/chatbox/OrderAttachments.js +2 -1
  100. package/src/chatbox/ProductAttachments.js +41 -5
  101. package/src/chatbox/TextMessage.js +21 -12
  102. package/src/chatbox/Typing.js +5 -1
  103. package/src/chatbox/Widget.js +34 -4
  104. package/src/chatbox/main.js +4 -1
  105. package/src/chatbox/spinner.js +1 -1
  106. package/src/chatbox/time.js +1 -1
  107. package/src/common.js +52 -8
  108. package/src/contact/contact.js +1 -1
  109. package/src/order/address_picker.js +235 -0
  110. package/src/order/icon.js +32 -0
  111. package/src/order/index.js +86 -0
  112. package/src/order/order.js +1157 -0
  113. package/src/order/scratch +211 -0
  114. package/src/plugin.js +7 -52
  115. package/src/store/api.js +26 -1
  116. package/src/store/store.js +53 -3
  117. package/src/util/common.js +48 -2
  118. package/up +1 -1
  119. package/webpack.dev.js +2 -0
  120. package/dist/17db8166252.178.js +0 -1
  121. package/dist/17db8166252.213.js +0 -1
  122. package/dist/17db8166252.362.js +0 -1
  123. package/dist/17db8166252.441.js +0 -1
  124. package/dist/17db8166252.605.js +0 -1
  125. package/dist/17db8166252.619.js +0 -1
  126. package/dist/17db8166252.74.js +0 -1
  127. package/dist/17db8166252.782.js +0 -1
  128. package/dist/17db8166252.app.js +0 -1
  129. package/dist/17db8166252.library.js +0 -1
  130. package/dist/17db8166252.preview.js +0 -1
  131. package/dist/17db8166252.screenshoot.js +0 -1
  132. package/dist/619.js +0 -777
  133. package/order.js +0 -0
  134. package/test.js +0 -1
@@ -0,0 +1,211 @@
1
+ renderShipping(order) {
2
+ let editmode = false
3
+ if (!order.status || order.status == 'new') {
4
+ editmode = !order.user_confirmation
5
+ }
6
+
7
+ let user = store.matchUser()
8
+ if (editmode) {
9
+ let addresses = store.matchShippingAddresses()
10
+
11
+ let $addrs = sb.map(addresses, (addr) => {
12
+ let fulladdr = [addr.street, addr.ward, addr.district, addr.region, addr.country].filter((a) => a).join(', ')
13
+ let cls = 'order__card'
14
+ if (this.state.shipping_address === addr.id) cls += ' order__card__active'
15
+ let $phone = null
16
+ if (addr.phone) {
17
+ $phone = (
18
+ <div style='margin-bottom:5px !important; '>
19
+ <img class='order_ship_icon' src={require('../../assets/img/phone.svg')} /> {addr.phone}
20
+ </div>
21
+ )
22
+ }
23
+ return (
24
+ <div class={cls}>
25
+ <div style='width: 100% !important;'>
26
+ <div class='radio'>
27
+ <input
28
+ type='radio'
29
+ id={'shipping_addr.' + addr.id}
30
+ onInput={(e) => this.onChangeShippingAddress(addr.id)}
31
+ name='shipping_address'
32
+ checked={this.state.shipping_address === addr.id}
33
+ />
34
+ <label class='radio--label ml-2' for={'shipping_addr.' + addr.id}>
35
+ Giao hàng tới <b>{addr.fullname}</b>
36
+ </label>
37
+ <div class='radio--check'>
38
+ <div class='inside'></div>
39
+ </div>
40
+ </div>
41
+ <div class='muted mt-1' style='margin-left: 30px !important;'>
42
+ {$phone}
43
+ <div>
44
+ <img class='order_ship_icon' src={require('../../assets/img/home.svg')} /> {fulladdr}
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ )
50
+ })
51
+
52
+ let provinces = sb.map(this.state.provinces, (province) => ({id: province.id, name: province.province}))
53
+ let districts = sb.map(this.state.districts, (district) => ({id: district.id, name: district.district}))
54
+ let wards = sb.map(this.state.wards, (ward) => ({id: ward.id, name: ward.ward}))
55
+ let cls = 'order__card'
56
+ let $new = null
57
+ if (this.state.shipping_address === 'new') {
58
+ cls += ' order__card__active'
59
+ $new = (
60
+ <div style='margin-left: 0px !important;'>
61
+ <div class='d-flex'>
62
+ <div class='mr-2' style='flex: 1 !important;'>
63
+ <div class='order_form_label'>{this.props.t('fullname')}</div>
64
+ <input type='text' class='form-control' onInput={this.onChangeFullname} value={this.state.fullname} />
65
+ </div>
66
+ <div class='ml-2' style='flex: 1 !important;'>
67
+ <div class='order_form_label'>{this.props.t('phone')}</div>
68
+ <input type='text' class='form-control' onInput={this.onChangePhone} value={this.state.phone} />
69
+ </div>
70
+ </div>
71
+
72
+ <div class='' style='width: 100% !important'>
73
+ <div class='order_form_label'>{this.props.t('address')}</div>
74
+ <input type='text' class='form-control' onInput={this.onChangeAddress} value={this.state.address} />
75
+ </div>
76
+
77
+ <div>
78
+ <div class='order_form_label'>{this.props.t('province')}</div>
79
+ <DropdownSelect
80
+ width='180'
81
+ has_search
82
+ loading={this.state.loadProvince}
83
+ full
84
+ items={provinces}
85
+ selected={this.state.selectedProvince}
86
+ onSelect={this.onSelectProvince}
87
+ />
88
+ </div>
89
+ <div>
90
+ <div class='order_form_label'>{this.props.t('district')}</div>
91
+ <DropdownSelect
92
+ width='180'
93
+ full
94
+ selected={this.state.selectedDistrict}
95
+ has_search
96
+ onSelect={this.onSelectDistrict}
97
+ loading={this.state.loadDistrict}
98
+ items={districts}
99
+ />
100
+ </div>
101
+
102
+ <div class='order_form_label'>{this.props.t('ward')}</div>
103
+ <DropdownSelect
104
+ width='180'
105
+ selected={this.state.selectedWard}
106
+ full
107
+ has_search
108
+ onSelect={this.onSelectWard}
109
+ loading={this.state.loadWard}
110
+ items={wards}
111
+ />
112
+ </div>
113
+ )
114
+ }
115
+
116
+ $addrs.push(
117
+ <div class={cls}>
118
+ <div style='width: 100% !important;'>
119
+ <div class='radio'>
120
+ <input
121
+ type='radio'
122
+ name='shipping_address'
123
+ id={'shipping_addr.new'}
124
+ onInput={(e) => this.onChangeShippingAddress('new')}
125
+ checked={this.state.shipping_address === 'new'}
126
+ />
127
+ <label class='radio--label ml-2' for={'shipping_addr.new'}>
128
+ <b>Giao hàng tới địa chỉ khác</b>
129
+ </label>
130
+ <div class='radio--check'>
131
+ <div class='inside'></div>
132
+ </div>
133
+ </div>
134
+ {$new}
135
+ </div>
136
+ </div>,
137
+ )
138
+
139
+ let shopcls = 'order__card'
140
+ let $shop = null
141
+ if (this.state.shipping_address === 'shop') {
142
+ shopcls += ' order__card__active'
143
+ $shop = (
144
+ <div>
145
+ <div class='d-flex'>
146
+ <div class='mr-2' style='flex: 3 !important;'>
147
+ <div class='order_form_label'>{this.props.t('fullname')}</div>
148
+ <input type='text' class='form-control' onInput={this.onChangeFullname} value={this.state.fullname} />
149
+ </div>
150
+ <div class='ml-2' style='flex: 2 !important;'>
151
+ <div class='order_form_label'>{this.props.t('phones')}</div>
152
+ <input type='text' class='form-control' onInput={this.onChangePhone} value={this.state.phone} />
153
+ </div>
154
+ </div>
155
+ <div>
156
+ <div class='order_form_label'>{this.props.t('email')}</div>
157
+ <input type='text' class='form-control' onInput={this.onChangeEmail} value={this.state.email} />
158
+ </div>
159
+ </div>
160
+ )
161
+ }
162
+
163
+ $addrs.unshift(
164
+ <div class={shopcls}>
165
+ <div style='width: 100% !important;'>
166
+ <div class='radio'>
167
+ <input
168
+ type='radio'
169
+ name='shipping_address'
170
+ id={'shipping_addr.shop'}
171
+ onInput={(e) => this.onChangeShippingAddress('shop')}
172
+ checked={this.state.shipping_address === 'shop'}
173
+ />
174
+ <label class='radio--label ml-2' for={'shipping_addr.shop'}>
175
+ <b>Nhận hàng tại shop</b>
176
+ </label>
177
+ <div class='radio--check'>
178
+ <div class='inside'></div>
179
+ </div>
180
+ </div>
181
+ {$shop}
182
+ </div>
183
+ </div>,
184
+ )
185
+ // let $oldaddress = sb.map()
186
+
187
+ return (
188
+ <div class='order_section'>
189
+ <div class='order_label'>{this.props.t('ship_to')}</div>
190
+ <div class='form'>{$addrs}</div>
191
+ </div>
192
+ )
193
+ }
194
+
195
+ let fulladdr = sb.get(order, 'shipping.address.full_address')
196
+ if (!fulladdr) return null
197
+ let $addr = fulladdr ? <div>{fulladdr}</div> : <i class='i muted'>Chưa có địa chỉ giao hàng</i>
198
+
199
+ return (
200
+ <div class='order_section'>
201
+ <div class='order_section_label'>{this.props.t('ship_to')}</div>
202
+ {$addr}
203
+ </div>
204
+ )
205
+ }
206
+
207
+
208
+
209
+ 1. ko co dia chi co san => dien luon new
210
+ 2. co dia chi => hien thi dia chi co san va option dia chi moi
211
+ 3.
package/src/plugin.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import sb from './util/index.js'
2
+ import * as common from './common.js'
2
3
  import {h, render, createRef} from 'preact'
3
4
 
4
5
  const LoadChatbox = () => import(/*webpackChunkName: "chatbox" */ './chatbox/main.js')
@@ -6,10 +7,6 @@ const LoadContact = () => import(/*webpackChunkName: "contact" */ './contact/con
6
7
  const LoadPopup = () => import(/*webpackChunkName: "popup" */ './popup/popup.js')
7
8
  const LoadNotif = () => import(/*webpackChunkName: "notif" */ './notif/notif.js')
8
9
 
9
- // cache lang messages
10
- let langMessages = {}
11
- let downloadLock = false
12
-
13
10
  function Plugin(plugin, store, $container, lib) {
14
11
  if (!$container) throw '$div must is a valid html node'
15
12
  var $div = document.createElement('div')
@@ -17,7 +14,7 @@ function Plugin(plugin, store, $container, lib) {
17
14
  $container.appendChild($div) // use body as container
18
15
 
19
16
  // auto detect language first
20
- let _locale = getLocale(plugin, sb.detectLang())
17
+ let _locale = common.getLocale(plugin, sb.detectLang())
21
18
 
22
19
  var domGate = new sb.Gate()
23
20
  var pageIndex = 0
@@ -136,11 +133,10 @@ function Plugin(plugin, store, $container, lib) {
136
133
  }
137
134
 
138
135
  // language
139
-
140
136
  let t = (key) => {
141
137
  if (_locale === 'debug') return `{{${key}}}`
142
138
 
143
- let messages = sb.get(langMessages, _locale, [])
139
+ let messages = sb.get(common.langMessages, _locale, [])
144
140
  let message = sb.find(messages, (message) => message.key === key)
145
141
  return sb.get(message, 'message', key)
146
142
  }
@@ -157,7 +153,7 @@ function Plugin(plugin, store, $container, lib) {
157
153
  t.locale = () => _locale
158
154
 
159
155
  this.forceDownloadLanguage = async () => {
160
- await downloadLanguage(store, _locale, true)
156
+ await common.downloadLanguage(store, _locale, true)
161
157
  this.update(plugin)
162
158
  }
163
159
 
@@ -167,8 +163,8 @@ function Plugin(plugin, store, $container, lib) {
167
163
  this.t = null
168
164
  _render() // hide plugin first
169
165
 
170
- _locale = getLocale(plugin, locale)
171
- await downloadLanguage(store, _locale)
166
+ _locale = common.getLocale(plugin, locale)
167
+ await common.downloadLanguage(store, _locale)
172
168
  this.t = t
173
169
  _render()
174
170
  return _locale
@@ -203,7 +199,7 @@ function Plugin(plugin, store, $container, lib) {
203
199
 
204
200
  this.update(plugin)
205
201
  // auto detect language firlst
206
- downloadLanguage(store, _locale).then(() => {
202
+ common.downloadLanguage(store, _locale).then(() => {
207
203
  this.t = t
208
204
  this.update(plugin)
209
205
  })
@@ -348,44 +344,3 @@ export default class PluginMgr {
348
344
  this._destroy = true
349
345
  }
350
346
  }
351
-
352
- function downloadLanguage(store, locale, force) {
353
- if (downloadLock)
354
- return new Promise((resolve) => setTimeout(() => downloadLanguage(store, locale, force).then(resolve), 100))
355
-
356
- downloadLock = true
357
- // let locale = getLocale()
358
- let messages
359
- if (locale === 'debug' || (langMessages[locale] && !force)) {
360
- downloadLock = false
361
- return Promise.resolve()
362
- }
363
-
364
- return store.getLocaleContent(locale).then((res) => {
365
- downloadLock = false
366
- messages = sb.get(res, 'body.messages', [])
367
- langMessages[locale] = messages
368
- })
369
- }
370
-
371
- const getLocale = (plugin, loc) => {
372
- if (!loc) loc = ''
373
- let found = sb.find(plugin.locales, (l) => l.toLowerCase().trim() === loc.toLowerCase().trim())
374
- if (found) return found
375
-
376
- found = sb.find(plugin.locales, (l) => {
377
- l = l
378
- .replace('-', '_')
379
- .split('_')[0]
380
- .trim()
381
- .toLowerCase()
382
- let compareloc = loc
383
- .replace('-', '_')
384
- .split('_')[0]
385
- .trim()
386
- .toLowerCase()
387
- return l == compareloc
388
- })
389
- if (found) return found
390
- return plugin.locale || 'en-US'
391
- }
package/src/store/api.js CHANGED
@@ -47,7 +47,10 @@ export default class {
47
47
  .get('/conversations')
48
48
 
49
49
  listMessages = (cid, limit, start_id) =>
50
- this.apireq.addQuery('limit', limit).addQuery('start_id', start_id).get(`/conversations/${cid}/messages`)
50
+ this.apireq
51
+ .addQuery('limit', limit)
52
+ .addQuery('start_id', start_id)
53
+ .get(`/conversations/${cid}/messages`)
51
54
 
52
55
  ajax = ajax
53
56
 
@@ -156,4 +159,26 @@ export default class {
156
159
  this.apireq.post(`/accounts/${this.accid}/campaigns/${impression.campaign_id}/impressions`, impression)
157
160
  sendConversion = (conversion) =>
158
161
  this.apireq.post(`/accounts/${this.accid}/campaigns/${conversion.campaign_id}/conversions`, conversion)
162
+
163
+ lookupOrder = (key) =>
164
+ ajax
165
+ .setBaseUrl(this.ApiURL)
166
+ .setContentType('text/plain')
167
+ .beforeHook(jsonifyTextPlain)
168
+ .setParser('json')
169
+ .addQuery('x-signed-key', key)
170
+ .get(`/orders/123`)
171
+
172
+ getOrder = (id) => this.apireq.get(`/accounts/${this.accid}/orders/` + id)
173
+ updateOrder = (order) => this.apireq.post(`/accounts/${this.accid}/orders/` + order.id, order)
174
+
175
+ fetchShippingAddresses = () => this.apireq.get(`/accounts/${this.accid}/users/${this.uid}/shipping-addresses`)
176
+ createShippingAddress = (addr) =>
177
+ this.apireq.post(`/accounts/${this.accid}/users/${this.uid}/shipping-addresses`, addr)
178
+
179
+ list_provinces = () => this.apireq.get(`/accounts/${this.accid}/provinces`)
180
+ list_districts = (p) => this.apireq.setQuery(p).get(`/accounts/${this.accid}/districts`)
181
+ list_wards = (p) => this.apireq.setQuery(p).get(`/accounts/${this.accid}/wards`)
182
+
183
+ suggest_address = (keyword) => this.apireq.setQuery({keyword: keyword}).get(`/accounts/${this.accid}/addresses`)
159
184
  }
@@ -80,6 +80,23 @@ export default class Store {
80
80
  return sb.Date.now() - (this.g_sync[key] || 0) < 300000
81
81
  }
82
82
 
83
+ async fetchShippingAddresses() {
84
+ let out = await this.api.fetchShippingAddresses()
85
+ if (out.error) return null
86
+ this.cache.put('shipping_address', out.body.shipping_addresses)
87
+ }
88
+
89
+ matchShippingAddresses() {
90
+ return this.cache.match('shipping_address')
91
+ }
92
+
93
+ updateOrder(order) {
94
+ return this.api.updateOrder(order)
95
+ }
96
+ createShippingAddress(addr) {
97
+ return this.api.createShippingAddress(addr)
98
+ }
99
+
83
100
  async overrideAcc(acc) {
84
101
  this.forceAcc = sb.cloneDeep(acc)
85
102
  await this.readyGate.entry()
@@ -176,8 +193,11 @@ export default class Store {
176
193
  return this.kv.match('user')
177
194
  }
178
195
 
196
+ suggest_addresses = (keyword) => this.api.suggest_address(keyword)
197
+
179
198
  matchSession = () => this.kv.match('session') || {}
180
199
  matchAccount = () => this.cache.match('account')
200
+ matchPaymentMethods = () => this.cache.match('payment_methods')
181
201
 
182
202
  matchUnread = () => {
183
203
  let user = this.matchUser()
@@ -231,6 +251,11 @@ export default class Store {
231
251
  return this.reconnectGate.open()
232
252
  }
233
253
 
254
+ list_provinces = () => this.api.list_provinces()
255
+ list_districts = (p) => this.api.list_districts(p)
256
+ list_wards = (p) => this.api.list_wards(p)
257
+
258
+ list_provices
234
259
  listEvents = (id) => {
235
260
  if (!id || id === '*' || typeof id !== 'string') return
236
261
  if (!this.isInsync('events' + id)) {
@@ -439,6 +464,7 @@ export default class Store {
439
464
  }
440
465
 
441
466
  _setUser(user) {
467
+ user = sb.cloneDeep(user)
442
468
  let olduser = this.kv.match('user') || {}
443
469
  var accid = olduser.account_id || user.account_id
444
470
  var id = olduser.id || user.id
@@ -536,6 +562,10 @@ export default class Store {
536
562
  this.cache.put('agent', agentM)
537
563
  }
538
564
 
565
+ // payment methods
566
+ let pms = sb.get(setting, 'payment_methods', [])
567
+ this.cache.put('payment_methods', pms)
568
+
539
569
  this.pubsub.publish('account')
540
570
  }
541
571
 
@@ -725,6 +755,14 @@ export default class Store {
725
755
  return {convo}
726
756
  }
727
757
 
758
+ fetchOrder(id) {
759
+ return this.api.getOrder(id)
760
+ }
761
+
762
+ lookupOrder(key) {
763
+ return this.api.lookupOrder(key)
764
+ }
765
+
728
766
  createPostback(cid, postback) {
729
767
  return this.api.createPostback(cid, postback)
730
768
  }
@@ -778,6 +816,14 @@ export default class Store {
778
816
  }
779
817
  this.onWs(ret)
780
818
  sendEventToThirdParty('SUBIZ Chat', 'Sent', 'User')
819
+ // send special event if user sent the first msg
820
+ let lastMsgSent = this.kv.match('last_msg_sent')
821
+ if (!lastMsgSent) {
822
+ let dataLayer = window.dataLayer || []
823
+ dataLayer.push({event: 'SUBIZ Chat', event_action: 'Sent', event_label: 'User', first_interaction: 1})
824
+ }
825
+
826
+ this.kv.put('last_msg_sent', sb.Date.now())
781
827
  }
782
828
 
783
829
  onConvoEvent = (o, cb) => this.pubsub.on2(o, 'events', cb)
@@ -825,7 +871,9 @@ export default class Store {
825
871
  setIsOpen = (isopen) => {
826
872
  let lastisopen = this.kv.match('isopen')
827
873
  this.kv.put('isopen', isopen)
828
- if (!lastisopen && isopen) sendEventToThirdParty('SUBIZ Chat', 'Opened', 'Subiz Windows')
874
+ if (!lastisopen && isopen) {
875
+ sendEventToThirdParty('SUBIZ Chat', 'Opened', 'Subiz Windows')
876
+ }
829
877
  }
830
878
  closePreview = () => this.kv.put('close_preview_at', new sb.Date().getTime())
831
879
  setLastview = (view, opts) => this.kv.put('lastview', {view, opts})
@@ -923,7 +971,7 @@ export default class Store {
923
971
  let startms = sb.Date.now()
924
972
 
925
973
  // store not init
926
- if (!sb.get(this.kv.match('user'), 'id')) return setTimeout(() => this.loopTime(), 30000)
974
+ if (!sb.get(this.kv.match('user'), 'id')) return setTimeout(() => this.loopTime(), 120000)
927
975
 
928
976
  let {body: t, error} = await this.api.time()
929
977
  if (error) return setTimeout(() => this.loopTime(), 30000)
@@ -931,7 +979,7 @@ export default class Store {
931
979
  var serverMs = new sb.Date(t).getTime() + latences
932
980
  var localMs = sb.Date.now()
933
981
  this.timeDiff = Math.floor(serverMs - localMs)
934
- setTimeout(() => this.loopTime(), 60000)
982
+ setTimeout(() => this.loopTime(), 120000)
935
983
  }
936
984
 
937
985
  replaceFileUrl(src) {
@@ -1091,6 +1139,8 @@ function sendEventToThirdParty(category, action, label) {
1091
1139
  document.dispatchEvent(new CustomEvent('subiz', {detail: {category, action, label}}))
1092
1140
  sendToGA(category, action, label)
1093
1141
  sendToFBPixel(category, action, label)
1142
+ let dataLayer = window.dataLayer || []
1143
+ dataLayer.push({event: category, event_action: action, event_label: label})
1094
1144
  }
1095
1145
 
1096
1146
  // from http://detectmobilebrowsers.com/
@@ -924,6 +924,7 @@ export function preloadWebfonts(fonts, done) {
924
924
  node.style.color = 'transparent'
925
925
  node.style.fontSize = '20px'
926
926
  node.style.height = '0px'
927
+ node.style.top = '0px'
927
928
  node.style.width = '0px'
928
929
 
929
930
  node.style.fontWeight = weight
@@ -1074,9 +1075,9 @@ export function getUrlParameter() {
1074
1075
  export var sleep = (ms) => new Promise((res) => setTimeout(res, ms))
1075
1076
 
1076
1077
  export function formatCurrency(val) {
1077
- if (!val) return 0
1078
+ if (!val) return '0 đ'
1078
1079
  val = Math.round(val)
1079
- return val.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
1080
+ return val.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')+ ' đ'
1080
1081
  }
1081
1082
 
1082
1083
  function replaceFileUrl(src) {
@@ -1106,3 +1107,48 @@ function replaceFileUrl(src) {
1106
1107
  src = src.replace('http://file.mysubiz.com/', fileurl)
1107
1108
  return src
1108
1109
  }
1110
+
1111
+ export function unicodeToAscii(str) {
1112
+ str = str + ''
1113
+ // worka round Đ not work
1114
+ str = str.replace('đ', 'd').replace('Đ', 'D')
1115
+ return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
1116
+ }
1117
+
1118
+ export function scrollIntoViewIfNeeded($ele) {
1119
+ centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded
1120
+
1121
+ var parent = $ele.parentNode
1122
+ var parentComputedStyle = window.getComputedStyle(parent, null)
1123
+ var parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width'))
1124
+ var parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width'))
1125
+ var overTop = $ele.offsetTop - parent.offsetTop < parent.scrollTop
1126
+ var overBottom =
1127
+ $ele.offsetTop - parent.offsetTop + $ele.clientHeight - parentBorderTopWidth >
1128
+ parent.scrollTop + parent.clientHeight
1129
+ var overLeft = $ele.offsetLeft - parent.offsetLeft < parent.scrollLeft
1130
+ var overRight =
1131
+ $ele.offsetLeft - parent.offsetLeft + $ele.clientWidth - parentBorderLeftWidth >
1132
+ parent.scrollLeft + parent.clientWidth
1133
+ var alignWithTop = overTop && !overBottom
1134
+
1135
+ if ((overTop || overBottom) && centerIfNeeded) {
1136
+ parent.scrollTop =
1137
+ $ele.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + $ele.clientHeight / 2
1138
+ }
1139
+
1140
+ if ((overLeft || overRight) && centerIfNeeded) {
1141
+ parent.scrollLeft =
1142
+ $ele.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + $ele.clientWidth / 2
1143
+ }
1144
+
1145
+ if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
1146
+ $ele.scrollIntoView(alignWithTop)
1147
+ }
1148
+ }
1149
+
1150
+ // if (!Element.prototype.scrollIntoViewIfNeeded) {
1151
+ //Element.prototype.scrollIntoViewIfNeeded = function(centerIfNeeded) {
1152
+
1153
+ //}
1154
+ //}
package/up CHANGED
@@ -38,6 +38,6 @@ sleep 5
38
38
 
39
39
  echo "Remove cloudfare cache"
40
40
  # PURGE CLOUD FLARE CACHE
41
- curl -X POST "https://api.cloudflare.com/client/v4/zones/cc22eff135a40705ebe59955b450217d/purge_cache" -H "X-Auth-Email: thanhpham@vietnambiz.com" -H "X-Auth-Key: $(cat ~/.cloudflare)" -H "Content-Type: application/javascript"
41
+ curl -X POST "https://api.cloudflare.com/client/v4/zones/e8f5c860cbbc130dd389313324a6c35e/purge_cache" -H "X-Auth-Email: thanhpham@vietnambiz.com" -H "X-Auth-Key: $(cat ~/.cloudflare)"
42
42
 
43
43
  echo "Success. $(cat dist/HASH)"
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
+ order: './src/order/index.js',
10
11
  screenshoot: './screenshoot.js',
11
12
  },
12
13
  output: {publicPath: '/'},
@@ -14,6 +15,7 @@ module.exports = {
14
15
  optimization: {minimize: false},
15
16
  plugins: [
16
17
  new HtmlWebpackPlugin({filename: './index.html', template: './index.html', inject: 'body', chunks: ['app']}),
18
+ new HtmlWebpackPlugin({filename: './order.html', template: './order.html', inject: 'body', chunks: ['order']}),
17
19
  new HtmlWebpackPlugin({filename: './preview.html', template: './preview.html', chunks: ['preview']}),
18
20
  new HtmlWebpackPlugin({filename: './inject.html', template: './inject.html', inject: 'body', chunks: ['inject']}),
19
21
  new HtmlWebpackPlugin({filename: './library.html', template: './index.html', inject: 'body', chunks: ['library']}),