@subiz/widget-v4 4.1.117 → 4.1.120

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 +36 -18
  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 +87 -13
  10. package/compiled_src/chatbox/Events.js +106 -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 +28 -23
  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 +88 -14
  33. package/src/chatbox/Events.js +93 -15
  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 +16 -18
  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.120",
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,87 @@ export default class Event extends Com {
149
152
  })
150
153
  }
151
154
 
152
- renderMessageSent() {
153
- let ev = this.props.event.ev
154
- 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} />
155
+ renderTyping() {
156
+ if (!this.props.event.is_show) {
157
+ return (
158
+ <div key={'container'} class='convo-event agent-message' style='opacity: 0 !important'>
159
+ <div class='agent-convo-event-wrapper'>
160
+ <div class='agent-convo-event-inner'>
161
+ <div class='message-agent message-text--agent' style='opacity: 0.6 !important'>
162
+ <div style='height: 20px !important; width: 35px !important'></div>
163
+ </div>
164
+ </div>
165
+ </div>
160
166
  </div>
161
167
  )
162
168
  }
163
- if (this.props.store.isAIDevMode()) $time = null
164
169
 
170
+ var html = `
171
+ <html>
172
+ <head>
173
+ <style>
174
+ .typing-container {
175
+ width: 100vw;
176
+ height: 100vh;
177
+ display: flex;
178
+ align-items: center;
179
+ gap: 4px;
180
+ justify-content: center;
181
+ }
182
+ .typing-dot {
183
+ display: inline-block;
184
+ vertical-align: middle;
185
+ width: 8px;
186
+ height: 8px;
187
+ background: black;
188
+ border-radius: 50%;
189
+ animation: typing 0.5s infinite alternate;
190
+ }
191
+ .typing-dot:nth-of-type(2) {
192
+ animation-delay: 0.2s;
193
+ }
194
+ .typing-dot:nth-of-type(3) {
195
+ animation-delay: 0.6s;
196
+ }
197
+ @keyframes typing {
198
+ 0% {
199
+ opacity: 0.9;
200
+ }
201
+ 100% {
202
+ opacity: 0.4;
203
+ }
204
+ }
205
+ </style>
206
+ </head>
207
+ <body style="padding: 0; margin: 0">
208
+ <div class="typing-container">
209
+ <span class="typing-dot"></span>
210
+ <span class="typing-dot"></span>
211
+ <span class="typing-dot"></span>
212
+ </div>
213
+ </body>
214
+ </html>
215
+ `
216
+ let src = 'data:text/html,' + encodeURIComponent(html)
217
+ return (
218
+ <div key={'container'} class='convo-event agent-message' style='opacity: 0.6 !important'>
219
+ <div class='agent-convo-event-wrapper'>
220
+ <div class='agent-convo-event-inner'>
221
+ <div class='message-agent message-text--agent'>
222
+ <iframe
223
+ src={src}
224
+ style='width: 35px !important; height: 20px !important; display: block !important; overflow: hidden !important; padding: 0 !important '
225
+ ></iframe>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ </div>
230
+ )
231
+ }
232
+
233
+ renderMessageSent() {
234
+ let ev = this.props.event.ev
235
+ this.tryLoadOrder(ev)
165
236
  let t = new sb.Date(ev.created).toLocaleString()
166
237
  // message of agent
167
238
  if (sb.get(ev, 'by.type') !== 'user') {
@@ -171,11 +242,16 @@ export default class Event extends Com {
171
242
  if (this.props.isLast) innercls += ' last'
172
243
  return (
173
244
  <div class='convo-event agent-message'>
174
- {$time}
175
245
  {$sender}
176
246
  <div class='agent-convo-event-wrapper'>
177
247
  <div class={innercls}>
178
- <TextMessage store={this.props.store} ev={ev} onLink={this.props.onLink} />
248
+ <TextMessage
249
+ showTime={this.props.event.show_time}
250
+ isLast={this.props.isLast}
251
+ store={this.props.store}
252
+ ev={ev}
253
+ onLink={this.props.onLink}
254
+ />
179
255
  <ImageAttachments store={this.props.store} ev={ev} />
180
256
  <AudioAttachments store={this.props.store} ev={ev} />
181
257
  <VideoAttachments store={this.props.store} ev={ev} />
@@ -223,7 +299,7 @@ export default class Event extends Com {
223
299
  }
224
300
 
225
301
  let $sender = null
226
- if (this.props.event.mode === 'lead') $sender = <div class='pt-3'></div>
302
+ if (this.props.event.mode === 'lead') $sender = <div class='pt-2'></div>
227
303
 
228
304
  let $error = null
229
305
  if (ev._error && ev.type === 'message_sent') {
@@ -239,7 +315,6 @@ export default class Event extends Com {
239
315
 
240
316
  return (
241
317
  <div class='convo-event user-message'>
242
- {$time}
243
318
  {$sender}
244
319
  <div class='message-user__container'>
245
320
  {$dot}
@@ -307,7 +382,6 @@ export default class Event extends Com {
307
382
 
308
383
  renderReactions() {
309
384
  if (this.props.store.isAIDevMode()) return null
310
-
311
385
  let ev = sb.get(this.props.event, 'ev') || {}
312
386
  let pongs = sb.get(ev, 'data.message.pongs') || []
313
387
  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,26 @@ 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
65
- }
113
+ // console.log('-----------', this.state.isShowTyping, this.state.typing_event)
114
+ let ev = this.state.typing_event || {id: 'evzz' + sb.Date.now(), created: sb.Date.now(), by: {type: 'agent'}}
115
+ let fakeev = {
116
+ is_typing: true,
117
+ is_show: this.state.isShowTyping,
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
+ },
66
126
  }
127
+ events.push(fakeev)
128
+ processEvents(convo, events)
67
129
 
68
130
  let $events = sb.map(events, (ev) => {
69
- let isLast = ev.ev.id === lastAgentMessageSentId
131
+ let isLast = ev.ev.id === sb.get(convo, 'last_message_sent.id')
70
132
  return (
71
133
  <Event
72
134
  isLast={isLast}
@@ -85,11 +147,18 @@ export default class Events extends Com {
85
147
 
86
148
  let $loading = null
87
149
  let style = 'opacity: 1 !important'
88
- if (this.state.loading || this.props.creating) {
150
+ if (this.props.creating) {
89
151
  $loading = <Spinner static mode={sb.get(this.props.chatbox, 'primary_color', 'dark')} size='120' center />
90
152
  style = 'opacity: 0 !important'
91
153
  }
92
154
 
155
+ if (this.state.loading) {
156
+ if (sb.Date.now() - this.state.loading > 500) {
157
+ $loading = <Spinner static mode={sb.get(this.props.chatbox, 'primary_color', 'dark')} size='120' center />
158
+ style = 'opacity: 0 !important'
159
+ }
160
+ }
161
+
93
162
  return (
94
163
  <Fragment>
95
164
  {$loading}
@@ -171,9 +240,13 @@ export default class Events extends Com {
171
240
  if (!this.props.cid) return
172
241
  // load msg
173
242
  this.lastContentOffsetY = 0
174
- this.setState({loading: true})
243
+ this.setState({loading: false})
175
244
  let events = this.props.store.listEvents(this.props.cid)
176
245
  if (sb.size(events) === 0) {
246
+ this.setState({loading: sb.Date.now()})
247
+ sb.setTimeout(() => {
248
+ this.forceUpdate()
249
+ }, 800)
177
250
  let cid = this.props.cid
178
251
 
179
252
  let {error} = await this.props.store.fetchMoreEvents(cid)
@@ -184,11 +257,10 @@ export default class Events extends Com {
184
257
  return
185
258
  }
186
259
  }
187
- this.setState({loading: true})
188
260
  this.props.store.fetchMoreEvents(this.props.cid)
189
261
  this.setState({error: false})
190
262
  this.scrollToBottom()
191
- sb.setTimeout(() => this.setState({loading: false}), 50)
263
+ // sb.setTimeout(() => this.setState({loading: false}), 50)
192
264
  }
193
265
 
194
266
  isBottom() {
@@ -205,7 +277,7 @@ export default class Events extends Com {
205
277
  sb.setTimeout(() => {
206
278
  const $div = this.refBody
207
279
  if ($div) $div.scrollTop = $div.scrollHeight
208
- }, 200)
280
+ }, 100)
209
281
 
210
282
  if (this.props.isShow) {
211
283
  if (this.props.store.browserVisibility === 'visible' && document.hasFocus()) {
@@ -224,9 +296,13 @@ function processEvents(convo, events) {
224
296
 
225
297
  // show time for the first msg sent
226
298
  // insert time
299
+ var lastAgentEvent
227
300
  for (var i = 1; i < events.length; i++) {
228
301
  let curEvent = events[i]
229
302
  let lastEvent = events[i - 1]
303
+ if (sb.get(curEvent, 'ev.by.type') != 'user' && !curEvent.is_typing) {
304
+ lastAgentEvent = curEvent
305
+ }
230
306
 
231
307
  if (visibleEvent(curEvent.ev)) {
232
308
  let elapsedSec = sb.unixSec(curEvent.ev.created) - sb.unixSec(lastEvent.ev.created)
@@ -234,6 +310,8 @@ function processEvents(convo, events) {
234
310
  }
235
311
  }
236
312
 
313
+ if (lastAgentEvent) lastAgentEvent.show_time = true
314
+
237
315
  for (var i = 0; i < events.length; i++) {
238
316
  let curEvent = events[i]
239
317
  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() {
@@ -625,8 +624,8 @@ export default class Widget extends Com {
625
624
  <div>{title}</div>
626
625
  {this.renderFields(form, formName)}
627
626
  </div>
628
- </div>
629
-
627
+ </div>
628
+ <div class="mt-2"></div>
630
629
  <PoweredBy store={this.props.store} t={this.props.t} />
631
630
  </div>
632
631
 
@@ -699,6 +698,7 @@ export default class Widget extends Com {
699
698
  <span>{this.props.t('start_conversation')}</span>
700
699
  <img src={send} alt='send button' width='26' height='26' />
701
700
  </button>
701
+ <div class="mt-2"></div>
702
702
  <PoweredBy store={this.props.store} />
703
703
  </div>
704
704
  </div>
@@ -776,17 +776,21 @@ export default class Widget extends Com {
776
776
  })
777
777
  if (_creating != this._creating) return // outdated
778
778
  if (error) {
779
+ this.setState({creating: false})
780
+ return
779
781
  // show error and try again
780
782
  }
781
783
  await this.props.store.sendConvoEvent(convo.id, 'message_sent', {message})
782
784
  if (_creating != this._creating) return // outdated
783
- this.setState({creating: false})
784
-
785
785
  this.props.onGo({view: 'chat', cid: convo.id})
786
+ this.setState({creating: false})
786
787
  return
787
788
  }
788
- await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
789
- this.setState({creating: false})
789
+ // dont let text-input wait, since we want to clear out the message as soon as posible
790
+ sb.setTimeout(async () => {
791
+ await this.props.store.sendConvoEvent(this.props.cid, 'message_sent', {message})
792
+ this.setState({creating: false})
793
+ }, 1)
790
794
  }
791
795
 
792
796
  createPostback(postback) {
@@ -804,6 +808,7 @@ export default class Widget extends Com {
804
808
  ref={this.msgInput}
805
809
  cid={this.props.cid}
806
810
  onChange={this.onChangeMessageInput}
811
+ is_loading={this.state.creating}
807
812
  onSend={this.sendMessage}
808
813
  t={this.props.t}
809
814
  />
@@ -818,7 +823,6 @@ export default class Widget extends Com {
818
823
  </div>
819
824
  )
820
825
  }
821
-
822
826
  return (
823
827
  <div class='widget-body'>
824
828
  <div class='widget-body--content' onClick={(e) => this.onContainerClick(e)}>
@@ -828,19 +832,13 @@ export default class Widget extends Com {
828
832
  store={this.props.store}
829
833
  chatbox={this.props.plugin.chatbox || {}}
830
834
  onFormSubmit={(e) => this.onEventFormSubmit(e)}
831
- ref={(ref) => (this.events = ref)}
835
+ ref={(ref) => (this.$events = ref)}
832
836
  cid={this.props.cid}
833
837
  creating={this.creating}
834
838
  onSend={(e) => this.sendMessage(e)}
835
839
  onPostback={(e) => this.createPostback(e)}
836
840
  t={this.props.t}
837
- />
838
- <Typing
839
- store={this.props.store}
840
- cid={this.props.cid}
841
- t={this.props.t}
842
841
  plugin={this.props.plugin}
843
- ref={this.refTyping}
844
842
  />
845
843
  </div>
846
844
  <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