@subiz/widget-v4 4.1.117 → 4.1.119

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 (56) hide show
  1. package/assets/less/base.less +1 -0
  2. package/assets/less/chatbox.less +2 -0
  3. package/assets/less/message.less +42 -22
  4. package/assets/less/message_input.less +2 -0
  5. package/assets/less/order.less +1 -1
  6. package/assets/less/widget.less +33 -16
  7. package/assets/less/widget_header.less +35 -36
  8. package/compiled_src/chatbox/AgentsAvatar.js +1 -1
  9. package/compiled_src/chatbox/Event.js +70 -15
  10. package/compiled_src/chatbox/Events.js +108 -19
  11. package/compiled_src/chatbox/Header.js +5 -4
  12. package/compiled_src/chatbox/InfoMessage.js +2 -13
  13. package/compiled_src/chatbox/MessageInput.js +19 -9
  14. package/compiled_src/chatbox/TextMessage.js +11 -2
  15. package/compiled_src/chatbox/Widget.js +22 -21
  16. package/compiled_src/chatbox/time.js +1 -0
  17. package/compiled_src/util/common.js +89 -0
  18. package/dist/185.js +19 -19
  19. package/dist/19641cfa41e.278.js +1 -0
  20. package/dist/19641cfa41e.app.js +1 -0
  21. package/dist/{195ec5442e3.index.html → 19641cfa41e.index.html} +1 -1
  22. package/dist/{195ec5442e3.library.html → 19641cfa41e.library.html} +1 -1
  23. package/dist/19641cfa41e.library.js +1 -0
  24. package/dist/{195ec5442e3.preview.html → 19641cfa41e.preview.html} +1 -1
  25. package/dist/19641cfa41e.preview.js +1 -0
  26. package/dist/19641cfa41e.webview.js +1 -0
  27. package/dist/278.js +1 -1
  28. package/dist/HASH +1 -1
  29. package/dist/screenshoot.js +562 -185
  30. package/package.json +2 -2
  31. package/src/chatbox/AgentsAvatar.js +1 -1
  32. package/src/chatbox/Event.js +76 -15
  33. package/src/chatbox/Events.js +95 -14
  34. package/src/chatbox/Header.js +3 -2
  35. package/src/chatbox/InfoMessage.js +0 -14
  36. package/src/chatbox/MessageInput.js +18 -7
  37. package/src/chatbox/TextMessage.js +13 -0
  38. package/src/chatbox/Widget.js +13 -16
  39. package/src/chatbox/time.js +12 -8
  40. package/src/util/common.js +121 -0
  41. package/up +33 -21
  42. package/compiled_src/chatbox/Typing.js +0 -77
  43. package/dist/195ec5442e3.278.js +0 -1
  44. package/dist/195ec5442e3.app.js +0 -1
  45. package/dist/195ec5442e3.library.js +0 -1
  46. package/dist/195ec5442e3.preview.js +0 -1
  47. package/dist/195ec5442e3.webview.js +0 -1
  48. package/src/chatbox/Typing.js +0 -72
  49. /package/dist/{195ec5442e3.127.js → 19641cfa41e.127.js} +0 -0
  50. /package/dist/{195ec5442e3.132.js → 19641cfa41e.132.js} +0 -0
  51. /package/dist/{195ec5442e3.185.js → 19641cfa41e.185.js} +0 -0
  52. /package/dist/{195ec5442e3.27.js → 19641cfa41e.27.js} +0 -0
  53. /package/dist/{195ec5442e3.459.js → 19641cfa41e.459.js} +0 -0
  54. /package/dist/{195ec5442e3.490.js → 19641cfa41e.490.js} +0 -0
  55. /package/dist/{195ec5442e3.74.js → 19641cfa41e.74.js} +0 -0
  56. /package/dist/{195ec5442e3.997.js → 19641cfa41e.997.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/widget-v4",
3
- "version": "4.1.117",
3
+ "version": "4.1.119",
4
4
  "main": "./compiled_src/lib.js",
5
5
  "scripts": {
6
6
  "dev": "npx webpack serve --config webpack.dev.js",
@@ -17,7 +17,7 @@
17
17
  "core-js": "^3.41.0",
18
18
  "css-loader": "5.2.7",
19
19
  "file-loader": "^6.2.0",
20
- "less": "^4.2.2",
20
+ "less": "^4.3.0",
21
21
  "less-loader": "^12.2.0",
22
22
  "preact": "10.19.3"
23
23
  },
@@ -38,7 +38,7 @@ export default function AgentsAvatar(props) {
38
38
  }
39
39
 
40
40
  agents = sb.filter(agents, (ag) => !!ag)
41
- if (agents.length === 0) {
41
+ if (agents.length === 0 || props.agent_ids === undefined || sb.size(props.agent_ids) === 0) {
42
42
  // use account avatar
43
43
  return (
44
44
  <div class={`group-avatar group-avatar--${mode}`}>
@@ -33,10 +33,13 @@ export default class Event extends Com {
33
33
  render() {
34
34
  var ev = sb.get(this.props.event, 'ev', {})
35
35
  switch (ev.type) {
36
+ case 'conversation_typing':
37
+ return this.renderTyping()
36
38
  case 'conversation_joined':
37
39
  // return this.renderMessageChatJoin()
38
40
  break
39
41
  case 'message_sent':
42
+ if (this.props.event.is_typing) return this.renderTyping()
40
43
  return this.renderMessageSent()
41
44
  case 'conversation_state_updated':
42
45
  case 'conversation_rating_requested':
@@ -149,19 +152,74 @@ export default class Event extends Com {
149
152
  })
150
153
  }
151
154
 
155
+ renderTyping() {
156
+ let innercls = 'agent-convo-event-inner'
157
+ var html = `
158
+ <html>
159
+ <head>
160
+ <style>
161
+ .typing-container {
162
+ width: 100vw;
163
+ height: 100vh;
164
+ display: flex;
165
+ align-items: center;
166
+ gap: 4px;
167
+ justify-content: center;
168
+ }
169
+ .typing-dot {
170
+ display: inline-block;
171
+ vertical-align: middle;
172
+ width: 8px;
173
+ height: 8px;
174
+ background: black;
175
+ border-radius: 50%;
176
+ animation: typing 0.5s infinite alternate;
177
+ }
178
+ .typing-dot:nth-of-type(2) {
179
+ animation-delay: 0.2s;
180
+ }
181
+ .typing-dot:nth-of-type(3) {
182
+ animation-delay: 0.6s;
183
+ }
184
+ @keyframes typing {
185
+ 0% {
186
+ opacity: 0.9;
187
+ }
188
+ 100% {
189
+ opacity: 0.4;
190
+ }
191
+ }
192
+ </style>
193
+ </head>
194
+ <body style="padding: 0; margin: 0">
195
+ <div class="typing-container">
196
+ <span class="typing-dot"></span>
197
+ <span class="typing-dot"></span>
198
+ <span class="typing-dot"></span>
199
+ </div>
200
+ </body>
201
+ </html>
202
+ `
203
+ let src = 'data:text/html,' + encodeURIComponent(html)
204
+ return (
205
+ <div class='convo-event agent-message'>
206
+ <div class='agent-convo-event-wrapper'>
207
+ <div class={innercls}>
208
+ <div class='message-agent message-text--agent' style='opacity: 0.6 !important'>
209
+ <iframe
210
+ src={src}
211
+ style='width: 35px !important; height: 20px !important; display: block !important; overflow: hidden !important; padding: 0 !important '
212
+ ></iframe>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ )
218
+ }
219
+
152
220
  renderMessageSent() {
153
221
  let ev = this.props.event.ev
154
222
  this.tryLoadOrder(ev)
155
- var $time = null
156
- if (this.props.event.show_time) {
157
- $time = (
158
- <div class='convo-event-time'>
159
- <Time time={ev.created} t={this.props.t} />
160
- </div>
161
- )
162
- }
163
- if (this.props.store.isAIDevMode()) $time = null
164
-
165
223
  let t = new sb.Date(ev.created).toLocaleString()
166
224
  // message of agent
167
225
  if (sb.get(ev, 'by.type') !== 'user') {
@@ -171,11 +229,16 @@ export default class Event extends Com {
171
229
  if (this.props.isLast) innercls += ' last'
172
230
  return (
173
231
  <div class='convo-event agent-message'>
174
- {$time}
175
232
  {$sender}
176
233
  <div class='agent-convo-event-wrapper'>
177
234
  <div class={innercls}>
178
- <TextMessage store={this.props.store} ev={ev} onLink={this.props.onLink} />
235
+ <TextMessage
236
+ showTime={this.props.event.show_time}
237
+ isLast={this.props.isLast}
238
+ store={this.props.store}
239
+ ev={ev}
240
+ onLink={this.props.onLink}
241
+ />
179
242
  <ImageAttachments store={this.props.store} ev={ev} />
180
243
  <AudioAttachments store={this.props.store} ev={ev} />
181
244
  <VideoAttachments store={this.props.store} ev={ev} />
@@ -223,7 +286,7 @@ export default class Event extends Com {
223
286
  }
224
287
 
225
288
  let $sender = null
226
- if (this.props.event.mode === 'lead') $sender = <div class='pt-3'></div>
289
+ // if (this.props.event.mode === 'lead') $sender = <div class='pt-3'></div>
227
290
 
228
291
  let $error = null
229
292
  if (ev._error && ev.type === 'message_sent') {
@@ -239,7 +302,6 @@ export default class Event extends Com {
239
302
 
240
303
  return (
241
304
  <div class='convo-event user-message'>
242
- {$time}
243
305
  {$sender}
244
306
  <div class='message-user__container'>
245
307
  {$dot}
@@ -307,7 +369,6 @@ export default class Event extends Com {
307
369
 
308
370
  renderReactions() {
309
371
  if (this.props.store.isAIDevMode()) return null
310
-
311
372
  let ev = sb.get(this.props.event, 'ev') || {}
312
373
  let pongs = sb.get(ev, 'data.message.pongs') || []
313
374
  let hasLike = this.hasLike()
@@ -29,10 +29,66 @@ export default class Events extends Com {
29
29
  this.checkAndSeen()
30
30
  }
31
31
 
32
+ componentDidMount() {
33
+ this.setState({
34
+ isShowTyping: false,
35
+ typing_event: {},
36
+ })
37
+
38
+ this.props.store.onConvoEvent(this, (ev) => {
39
+ if (sb.convoOfEv(ev) !== this.props.cid) return
40
+ // if (sb.get(ev, 'by.id') === user.id) return
41
+ // fixwidget in dashboard show typing of user
42
+ if (sb.get(ev, 'by.type') === 'user') return
43
+
44
+ let oldby = sb.get(this.state.typing_event, 'by.id')
45
+ if (oldby && sb.get(ev, 'by.id') !== oldby) return
46
+
47
+ if (sb.get(ev, 'type') === 'message_sent') {
48
+ // stop the typing
49
+ if (this.timer) sb.clearTimeout(this.timer)
50
+ this.timer = null
51
+ this.setState({isShowTyping: false})
52
+ return
53
+ }
54
+ if (sb.get(ev, 'type') !== 'conversation_typing') return
55
+
56
+ // dont show typing of agent, some agent dont like this
57
+ let ag = this.props.store.matchAgent(sb.get(ev, 'by.id')) || {}
58
+ if (ag.type == 'agent' && !sb.get(this.props.plugin, 'chatbox.show_agent_typing')) return
59
+ this.setState({typing_event: ev, isShowTyping: true})
60
+ if (this.timer) sb.clearTimeout(this.timer)
61
+ this.timer = sb.setTimeout(() => {
62
+ if (sb.convoOfEv(ev) !== this.props.cid) return
63
+ this.timer = null
64
+ this.setState({isShowTyping: false})
65
+ }, 5000)
66
+ })
67
+ }
68
+
32
69
  componentDidUpdate(prevProps) {
33
70
  if (prevProps.cid !== this.props.cid) this.loadConvo()
34
71
  }
35
72
 
73
+ ShowTyping() {
74
+ this.setState({
75
+ isShowTyping: true,
76
+ typing_event: {
77
+ id: 'evzz' + sb.Date.now(),
78
+ created: sb.Date.now(),
79
+ by: {
80
+ type: 'agent',
81
+ },
82
+ type: 'conversation_typing',
83
+ },
84
+ })
85
+ if (this.timer) sb.clearTimeout(this.timer)
86
+ this.timer = sb.setTimeout(() => {
87
+ this.timer = null
88
+ this.setState({isShowTyping: false})
89
+ }, 5000)
90
+ }
91
+
36
92
  render() {
37
93
  if (this.state.error) return this.renderError()
38
94
  let events = sb.map(this.props.store.listEvents(this.props.cid))
@@ -53,20 +109,29 @@ export default class Events extends Com {
53
109
 
54
110
  let convo = this.props.store.matchConvo(this.props.cid)
55
111
  events = sb.map(events, (ev) => ({ev: ev}))
56
- processEvents(convo, events)
57
112
 
58
- let lastAgentMessageSentId = ''
59
- for (let i = events.length - 1; i >= 0; i--) {
60
- let ev = sb.get(events, [i, 'ev']) || {}
61
- let bytype = sb.get(ev, 'by.type')
62
- if (bytype !== 'user' && ev.type === 'message_sent') {
63
- lastAgentMessageSentId = ev.id
64
- break
113
+ // console.log('-----------', this.state.isShowTyping, this.state.typing_event)
114
+ if (this.state.isShowTyping) {
115
+ let ev = this.state.typing_event || {id: 'evzz' + sb.Date.now(), created: sb.Date.now(), by: {type: 'agent'}}
116
+ let fakeev = {
117
+ is_typing: true,
118
+ id: ev.id,
119
+ ev: {
120
+ id: ev.id,
121
+ created: ev.created,
122
+ by: ev.by,
123
+ type: 'message_sent',
124
+ data: {message: {text: '...', conversation_id: this.props.cid}},
125
+ },
65
126
  }
127
+ console.log('FA', fakeev)
128
+ events.push(fakeev)
66
129
  }
67
130
 
131
+ processEvents(convo, events)
132
+
68
133
  let $events = sb.map(events, (ev) => {
69
- let isLast = ev.ev.id === lastAgentMessageSentId
134
+ let isLast = ev.ev.id === sb.get(convo, 'last_message_sent.id')
70
135
  return (
71
136
  <Event
72
137
  isLast={isLast}
@@ -85,11 +150,18 @@ export default class Events extends Com {
85
150
 
86
151
  let $loading = null
87
152
  let style = 'opacity: 1 !important'
88
- if (this.state.loading || this.props.creating) {
153
+ if (this.props.creating) {
89
154
  $loading = <Spinner static mode={sb.get(this.props.chatbox, 'primary_color', 'dark')} size='120' center />
90
155
  style = 'opacity: 0 !important'
91
156
  }
92
157
 
158
+ if (this.state.loading) {
159
+ if (sb.Date.now() - this.state.loading > 500) {
160
+ $loading = <Spinner static mode={sb.get(this.props.chatbox, 'primary_color', 'dark')} size='120' center />
161
+ style = 'opacity: 0 !important'
162
+ }
163
+ }
164
+
93
165
  return (
94
166
  <Fragment>
95
167
  {$loading}
@@ -171,9 +243,13 @@ export default class Events extends Com {
171
243
  if (!this.props.cid) return
172
244
  // load msg
173
245
  this.lastContentOffsetY = 0
174
- this.setState({loading: true})
246
+ this.setState({loading: false})
175
247
  let events = this.props.store.listEvents(this.props.cid)
176
248
  if (sb.size(events) === 0) {
249
+ this.setState({loading: sb.Date.now()})
250
+ sb.setTimeout(() => {
251
+ this.forceUpdate()
252
+ }, 800)
177
253
  let cid = this.props.cid
178
254
 
179
255
  let {error} = await this.props.store.fetchMoreEvents(cid)
@@ -184,11 +260,10 @@ export default class Events extends Com {
184
260
  return
185
261
  }
186
262
  }
187
- this.setState({loading: true})
188
263
  this.props.store.fetchMoreEvents(this.props.cid)
189
264
  this.setState({error: false})
190
265
  this.scrollToBottom()
191
- sb.setTimeout(() => this.setState({loading: false}), 50)
266
+ // sb.setTimeout(() => this.setState({loading: false}), 50)
192
267
  }
193
268
 
194
269
  isBottom() {
@@ -205,7 +280,7 @@ export default class Events extends Com {
205
280
  sb.setTimeout(() => {
206
281
  const $div = this.refBody
207
282
  if ($div) $div.scrollTop = $div.scrollHeight
208
- }, 200)
283
+ }, 100)
209
284
 
210
285
  if (this.props.isShow) {
211
286
  if (this.props.store.browserVisibility === 'visible' && document.hasFocus()) {
@@ -224,9 +299,13 @@ function processEvents(convo, events) {
224
299
 
225
300
  // show time for the first msg sent
226
301
  // insert time
302
+ var lastAgentEvent
227
303
  for (var i = 1; i < events.length; i++) {
228
304
  let curEvent = events[i]
229
305
  let lastEvent = events[i - 1]
306
+ if (sb.get(curEvent, 'ev.by.type') != 'user' && !curEvent.is_typing) {
307
+ lastAgentEvent = curEvent
308
+ }
230
309
 
231
310
  if (visibleEvent(curEvent.ev)) {
232
311
  let elapsedSec = sb.unixSec(curEvent.ev.created) - sb.unixSec(lastEvent.ev.created)
@@ -234,6 +313,8 @@ function processEvents(convo, events) {
234
313
  }
235
314
  }
236
315
 
316
+ if (lastAgentEvent) lastAgentEvent.show_time = true
317
+
237
318
  for (var i = 0; i < events.length; i++) {
238
319
  let curEvent = events[i]
239
320
  if (sb.get(curEvent, 'ev.type') === 'message_sent') {
@@ -54,7 +54,8 @@ export default class Header extends Com {
54
54
  return (
55
55
  <div class={cls} style={style}>
56
56
  {$back}
57
- <AgentsAvatar plugin={this.props.plugin} store={this.props.store} mode='secondary' agent_ids={agentIdsJoined} />
57
+ <div class="mr-2"></div>
58
+ <AgentsAvatar plugin={this.props.plugin} store={this.props.store} mode='secondary' />
58
59
  <div class='widget-header--title-container'>
59
60
  <div class='widget-header--title'>{this.getTitle()}</div>
60
61
  <div class='widget-header--description' title={desc}>
@@ -201,7 +202,7 @@ Vui lòng hỏi chúng tôi bất cứ điều gì hoặc chia sẻ phản hồi
201
202
  if (accSetting.hide_close_button) return null
202
203
  return (
203
204
  <div
204
- class='widget-header--button widget-header--button-close'
205
+ class='widget-header--button-close'
205
206
  data-tooltip={this.props.t('close')}
206
207
  data-tooltip-position='bottom'
207
208
  onClick={(e) => this.onCloseClick(e)}
@@ -7,24 +7,12 @@ function getRateLang(rating) {
7
7
  return 'great'
8
8
  }
9
9
 
10
- import Time from './time.js'
11
10
  import {Com} from '../common.js'
12
11
  import {h} from 'preact'
13
12
  // [ 'ev'],
14
13
  export default class InfoMessage extends Com {
15
14
  render() {
16
15
  let ev = this.props.ev.ev
17
- var $time = null
18
-
19
- if (this.props.ev.show_time) {
20
- $time = (
21
- <div class='convo-event-time'>
22
- <Time time={ev.created} t={this.props.t} />
23
- </div>
24
- )
25
- }
26
-
27
- if (this.props.store.isAIDevMode()) $time = null
28
16
 
29
17
  // if (this.ev.type === 'conversation_rating_requested') return <div class="info-message"></div>
30
18
  if (ev.type === 'conversation_rated') {
@@ -32,7 +20,6 @@ export default class InfoMessage extends Com {
32
20
  if (rating.no_rating) return null
33
21
  return (
34
22
  <div class='convo-event'>
35
- {$time}
36
23
  <div class='info-message'>
37
24
  {this.props.t('rated_as') + ' ' + this.props.t(getRateLang(rating.rating)).toLowerCase()}
38
25
  </div>
@@ -42,7 +29,6 @@ export default class InfoMessage extends Com {
42
29
  if (ev.type === 'conversation_state_updated' && sb.get(ev, 'data.conversation.state') === 'ended') {
43
30
  return (
44
31
  <div class='convo-event'>
45
- {$time}
46
32
  <div class='info-message'>{this.props.t('conversation_ended')}</div>
47
33
  </div>
48
34
  )
@@ -1,8 +1,9 @@
1
1
  import sb from '../util/index.js'
2
2
  import {Com} from '../common.js'
3
3
  import {h, createRef} from 'preact'
4
+ import Spinner from './spinner.js'
4
5
  import Emoji from './Emoji.js'
5
- // props: ['disabled', 'cid'],
6
+ // props: ['disabled', 'cid', 'is_loading'],
6
7
  export default class MessageInput extends Com {
7
8
  constructor(props) {
8
9
  super(props)
@@ -37,7 +38,7 @@ export default class MessageInput extends Com {
37
38
  }
38
39
 
39
40
  render() {
40
- var buttons = (
41
+ var $buttons = (
41
42
  <div class='d-flex flex-row align-self-end'>
42
43
  {this.renderEmoji()}
43
44
  <div
@@ -49,7 +50,7 @@ export default class MessageInput extends Com {
49
50
  )
50
51
  var msg = sb.trim(this.state.msgValue)
51
52
  if (msg.length > 0) {
52
- buttons = (
53
+ $buttons = (
53
54
  <div class='d-flex flex-row align-self-end'>
54
55
  {this.renderEmoji()}
55
56
  <div
@@ -61,9 +62,17 @@ export default class MessageInput extends Com {
61
62
  )
62
63
  }
63
64
 
65
+ if (this.props.is_loading) {
66
+ $buttons = (
67
+ <div class='d-flex flex-row align-self-end'>
68
+ <Spinner size='32' />
69
+ </div>
70
+ )
71
+ }
72
+
64
73
  var containercls = ''
65
74
  var disabled = this.hasUnfinishRequiredFormOrLock() || this.props.disabled
66
- if (disabled) containercls = 'message-input--disabled'
75
+ if (disabled || this.props.is_loading) containercls = 'message-input--disabled'
67
76
 
68
77
  return (
69
78
  <div
@@ -77,7 +86,7 @@ export default class MessageInput extends Com {
77
86
  disabled={disabled}
78
87
  class='message-input--input'
79
88
  maxlength='1024'
80
- placeholder={this.props.t('message_input_help')}
89
+ placeholder={this.props.t('message_input_help').substr(0, 25)}
81
90
  ref={this.refMessageInput}
82
91
  rows='1'
83
92
  value={this.state.msgValue}
@@ -86,7 +95,7 @@ export default class MessageInput extends Com {
86
95
  data-emojiable='true'
87
96
  onKeydown={(e) => this.onKeydown(e)}
88
97
  />
89
- {buttons}
98
+ {$buttons}
90
99
  </div>
91
100
  )
92
101
  }
@@ -324,9 +333,11 @@ export default class MessageInput extends Com {
324
333
  msg = msg || sb.trim(this.state.msgValue) || ''
325
334
  if (!msg) return
326
335
  if (this.props.disabled) return
336
+ if (this.props.onSend) {
337
+ await this.props.onSend({text: msg, format: 'plaintext'})
338
+ }
327
339
  this.setState({openEmoji: false, msgValue: ''})
328
340
  this.resizeInput()
329
- this.props.onSend && this.props.onSend({text: msg, format: 'plaintext'})
330
341
  }
331
342
 
332
343
  sendTyping() {
@@ -3,8 +3,19 @@ import Block from './block.js'
3
3
  import {Com} from '../common.js'
4
4
  import {h} from 'preact'
5
5
  import Emoji from './Emoji.js'
6
+ import Time from './time.js'
6
7
 
7
8
  export default class TextMessage extends Com {
9
+ renderTime() {
10
+ if (!this.props.showTime && !this.props.isLast && !this.props.isFirst) return null
11
+
12
+ return (
13
+ <div>
14
+ <Time class='inline-time' time={sb.get(this.props.ev, 'created', sb.Date.now())} t={this.props.t} />
15
+ </div>
16
+ )
17
+ }
18
+
8
19
  render() {
9
20
  var format = sb.get(this.props.ev, 'data.message.format', 'plaintext')
10
21
  let block = sb.get(this.props.ev, 'data.message.block')
@@ -48,6 +59,7 @@ export default class TextMessage extends Com {
48
59
  return (
49
60
  <div class='message-agent message-text--agent' title={t}>
50
61
  {tags}
62
+ {this.renderTime()}
51
63
  </div>
52
64
  )
53
65
  return (
@@ -66,6 +78,7 @@ export default class TextMessage extends Com {
66
78
  return (
67
79
  <div class='message-agent message-text--agent' title={t}>
68
80
  <Block block={block} onLink={this.props.onLink} />
81
+ {this.renderTime()}
69
82
  </div>
70
83
  )
71
84
  }
@@ -8,7 +8,7 @@ var checkedimg = require('../../assets/img/done_gray.svg')
8
8
  var empty = require('../../assets/img/empty.svg')
9
9
  import MessageInput from './MessageInput.js'
10
10
  import Events from './Events.js'
11
- import Typing from './Typing.js'
11
+ // import Typing from './Typing.js'
12
12
  import Rating from './Rating.js'
13
13
  // import Order from './Order.js'
14
14
  let Order = false
@@ -17,7 +17,6 @@ import ListField from './ListField.js'
17
17
 
18
18
  const defaultAvatar = 'https://vcdn.subiz-cdn.com/file/fiqoahedjbgwclpouoml-avatar_default_baa8a1d7.png'
19
19
 
20
- import Spinner from './spinner.js'
21
20
  import Time from './time.js'
22
21
  import {Com} from '../common.js'
23
22
  import {h, createRef} from 'preact'
@@ -68,7 +67,7 @@ export default class Widget extends Com {
68
67
  // focus Events then focus MessageInput
69
68
  // if there is any pending form, MessageInput will be disabled
70
69
  // and dont steal focus from Events
71
- this.events && this.events.focus()
70
+ this.$events && this.$events.focus()
72
71
  if (!this.props.store.isMobile()) this.focusInput()
73
72
  }, 100)
74
73
  this.updateFormDataFields()
@@ -77,7 +76,7 @@ export default class Widget extends Com {
77
76
  }
78
77
 
79
78
  ShowTyping() {
80
- this.refTyping.current && this.refTyping.current.ShowTyping()
79
+ this.$events && this.$events.ShowTyping()
81
80
  }
82
81
 
83
82
  shouldShowForm() {
@@ -776,17 +775,21 @@ export default class Widget extends Com {
776
775
  })
777
776
  if (_creating != this._creating) return // outdated
778
777
  if (error) {
778
+ this.setState({creating: false})
779
+ return
779
780
  // show error and try again
780
781
  }
781
782
  await this.props.store.sendConvoEvent(convo.id, 'message_sent', {message})
782
783
  if (_creating != this._creating) return // outdated
783
- this.setState({creating: false})
784
-
785
784
  this.props.onGo({view: 'chat', cid: convo.id})
785
+ this.setState({creating: false})
786
786
  return
787
787
  }
788
- await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
789
- this.setState({creating: false})
788
+ // dont let text-input wait, since we want to clear out the message as soon as posible
789
+ sb.setTimeout(async () => {
790
+ await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
791
+ this.setState({creating: false})
792
+ }, 1)
790
793
  }
791
794
 
792
795
  createPostback(postback) {
@@ -804,6 +807,7 @@ export default class Widget extends Com {
804
807
  ref={this.msgInput}
805
808
  cid={this.props.cid}
806
809
  onChange={this.onChangeMessageInput}
810
+ is_loading={this.state.creating}
807
811
  onSend={this.sendMessage}
808
812
  t={this.props.t}
809
813
  />
@@ -818,7 +822,6 @@ export default class Widget extends Com {
818
822
  </div>
819
823
  )
820
824
  }
821
-
822
825
  return (
823
826
  <div class='widget-body'>
824
827
  <div class='widget-body--content' onClick={(e) => this.onContainerClick(e)}>
@@ -828,19 +831,13 @@ export default class Widget extends Com {
828
831
  store={this.props.store}
829
832
  chatbox={this.props.plugin.chatbox || {}}
830
833
  onFormSubmit={(e) => this.onEventFormSubmit(e)}
831
- ref={(ref) => (this.events = ref)}
834
+ ref={(ref) => (this.$events = ref)}
832
835
  cid={this.props.cid}
833
836
  creating={this.creating}
834
837
  onSend={(e) => this.sendMessage(e)}
835
838
  onPostback={(e) => this.createPostback(e)}
836
839
  t={this.props.t}
837
- />
838
- <Typing
839
- store={this.props.store}
840
- cid={this.props.cid}
841
- t={this.props.t}
842
840
  plugin={this.props.plugin}
843
- ref={this.refTyping}
844
841
  />
845
842
  </div>
846
843
  <Rating
@@ -28,13 +28,13 @@ export default class Time extends Com {
28
28
  if (this.props.short) {
29
29
  // more than 10 days
30
30
  //if (Math.abs(this.props.time - new sb.Date().getTime()) > 86400000 * 10) {
31
- //let tim = new sb.Date(this.props.time)
32
- //let tzyear = tim.getFullYear()
33
- //let locale = sb.get(navigator, 'languages.0', 'en-US')
34
- //if (forceLocale) locale = forceLocale
35
- //let tzmonthname = tim.toLocaleDateString(locale, {month: 'short'})
36
- //let tzdate = tim.getDate()
37
- //t = tzdate + ' ' + tzmonthname + ' ' + tzyear
31
+ //let tim = new sb.Date(this.props.time)
32
+ //let tzyear = tim.getFullYear()
33
+ //let locale = sb.get(navigator, 'languages.0', 'en-US')
34
+ //if (forceLocale) locale = forceLocale
35
+ //let tzmonthname = tim.toLocaleDateString(locale, {month: 'short'})
36
+ //let tzdate = tim.getDate()
37
+ //t = tzdate + ' ' + tzmonthname + ' ' + tzyear
38
38
  //}
39
39
  }
40
40
 
@@ -61,7 +61,11 @@ export default class Time extends Com {
61
61
  }
62
62
  }
63
63
  let title = new Date(this.props.time).toLocaleString(locale)
64
- return <span style={this.props.style} title={title}>{this.state.t}</span>
64
+ return (
65
+ <span class={this.props.class} style={this.props.style} title={title}>
66
+ {this.state.t}
67
+ </span>
68
+ )
65
69
  }
66
70
  }
67
71