@subiz/widget-v4 4.1.187 → 4.1.191

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 (114) hide show
  1. package/assets/less/message.less +27 -11
  2. package/assets/less/widget.less +1 -1
  3. package/compiled_src/chatbox/Buttons.js +2 -2
  4. package/compiled_src/chatbox/ChatButton.js +12 -4
  5. package/compiled_src/chatbox/Event.js +19 -6
  6. package/compiled_src/chatbox/Events.js +11 -2
  7. package/compiled_src/chatbox/Widget.js +3 -1
  8. package/compiled_src/chatbox/main.js +15 -1
  9. package/compiled_src/store/store.js +1 -1
  10. package/compiled_src/util/common.js +7 -4
  11. package/package.json +4 -4
  12. package/src/chatbox/Buttons.js +2 -2
  13. package/src/chatbox/ChatButton.js +12 -1
  14. package/src/chatbox/Event.js +26 -11
  15. package/src/chatbox/Events.js +17 -2
  16. package/src/chatbox/Widget.js +5 -1
  17. package/src/chatbox/main.js +8 -1
  18. package/src/store/store.js +1 -1
  19. package/src/util/common.js +4 -1
  20. package/dist/127.js +0 -273
  21. package/dist/132.js +0 -2802
  22. package/dist/185.js +0 -1827
  23. package/dist/19a00a03cb8.127.js +0 -1
  24. package/dist/19a00a03cb8.132.js +0 -1
  25. package/dist/19a00a03cb8.185.js +0 -1
  26. package/dist/19a00a03cb8.27.js +0 -1
  27. package/dist/19a00a03cb8.278.js +0 -1
  28. package/dist/19a00a03cb8.339.js +0 -1
  29. package/dist/19a00a03cb8.459.js +0 -1
  30. package/dist/19a00a03cb8.490.js +0 -1
  31. package/dist/19a00a03cb8.74.js +0 -1
  32. package/dist/19a00a03cb8.997.js +0 -1
  33. package/dist/19a00a03cb8.app.js +0 -1
  34. package/dist/19a00a03cb8.chat.html +0 -1
  35. package/dist/19a00a03cb8.chat.js +0 -1
  36. package/dist/19a00a03cb8.form.html +0 -1
  37. package/dist/19a00a03cb8.form.js +0 -1
  38. package/dist/19a00a03cb8.index.html +0 -72
  39. package/dist/19a00a03cb8.library.html +0 -72
  40. package/dist/19a00a03cb8.library.js +0 -1
  41. package/dist/19a00a03cb8.preview.html +0 -759
  42. package/dist/19a00a03cb8.preview.js +0 -1
  43. package/dist/19a00a03cb8.webview.js +0 -1
  44. package/dist/27.js +0 -35
  45. package/dist/459.js +0 -35
  46. package/dist/490.js +0 -305
  47. package/dist/74.js +0 -372
  48. package/dist/997.js +0 -35
  49. package/dist/HASH +0 -1
  50. package/dist/assets/img/Facebook.64607ec.png +0 -0
  51. package/dist/assets/img/Zalo.6845707.png +0 -0
  52. package/dist/assets/img/award1a.1a58e10.png +0 -0
  53. package/dist/assets/img/award3a.3b74423.png +0 -0
  54. package/dist/assets/img/award4a.ed6ccd4.png +0 -0
  55. package/dist/assets/img/award5.39eb7ae.png +0 -0
  56. package/dist/assets/img/bubble_default.7d5e4ab.svg +0 -20
  57. package/dist/assets/img/caret.998eb8f.svg +0 -1
  58. package/dist/assets/img/convos_empty.2353007.svg +0 -72
  59. package/dist/assets/img/default.06e6ee0.jpg +0 -0
  60. package/dist/assets/img/default_avatar.5b74dc1.png +0 -0
  61. package/dist/assets/img/done_gray.d7e8203.svg +0 -4
  62. package/dist/assets/img/done_green.b817fd4.svg +0 -4
  63. package/dist/assets/img/emoji/messenger/sub_23.529_58.824.d5faf14.png +0 -0
  64. package/dist/assets/img/emoji/messenger/sub_23.529_60.784.1420241.png +0 -0
  65. package/dist/assets/img/emoji/messenger/sub_25.490_0.000.1e6b2c0.png +0 -0
  66. package/dist/assets/img/emoji/messenger/sub_25.490_45.098.3dfbc08.png +0 -0
  67. package/dist/assets/img/emoji/messenger/sub_25.490_5.882.4b49e94.png +0 -0
  68. package/dist/assets/img/emoji/messenger/sub_27.451_72.549.7114f58.png +0 -0
  69. package/dist/assets/img/emoji/messenger/sub_27.451_84.314.231e2b7.png +0 -0
  70. package/dist/assets/img/emoji/messenger/sub_27.451_96.078.ddbb008.png +0 -0
  71. package/dist/assets/img/emoji/messenger/sub_29.412_5.882.61f3359.png +0 -0
  72. package/dist/assets/img/emoji/messenger/sub_58.824_100.000.6df72bc.png +0 -0
  73. package/dist/assets/img/emoji/messenger/sub_58.824_45.098.3d7a7ad.png +0 -0
  74. package/dist/assets/img/emoji/messenger/sub_58.824_47.059.0f4d6e2.png +0 -0
  75. package/dist/assets/img/emoji/messenger/sub_58.824_54.902.65724c1.png +0 -0
  76. package/dist/assets/img/emoji/messenger/sub_58.824_64.706.9da3cba.png +0 -0
  77. package/dist/assets/img/emoji/messenger/sub_58.824_72.549.edca5cf.png +0 -0
  78. package/dist/assets/img/emoji/messenger/sub_58.824_78.431.f910f2a.png +0 -0
  79. package/dist/assets/img/emoji/messenger/sub_58.824_88.235.def4e71.png +0 -0
  80. package/dist/assets/img/emoji/messenger/sub_60.784_11.765.49c03d0.png +0 -0
  81. package/dist/assets/img/emoji/messenger/sub_60.784_27.451.46b54e5.png +0 -0
  82. package/dist/assets/img/emoji/messenger/sub_60.784_29.412.e36d284.png +0 -0
  83. package/dist/assets/img/emoji/messenger/sub_60.784_3.922.bb191b0.png +0 -0
  84. package/dist/assets/img/emoji/messenger/sub_60.784_35.294.af7b927.png +0 -0
  85. package/dist/assets/img/emoji/messenger/sub_60.784_7.843.98f2a99.png +0 -0
  86. package/dist/assets/img/empty.29bed2d.svg +0 -23
  87. package/dist/assets/img/empty_1.0b98af0.svg +0 -11
  88. package/dist/assets/img/examplte_logo.f86535f.svg +0 -1
  89. package/dist/assets/img/external-link.90577cc.svg +0 -1
  90. package/dist/assets/img/fb_inverse_circle.36c2cfc.png +0 -0
  91. package/dist/assets/img/ghn.070f8e3.svg +0 -17
  92. package/dist/assets/img/ghtk.326eac1.svg +0 -18
  93. package/dist/assets/img/image_default.be0698b.png +0 -0
  94. package/dist/assets/img/info.ebce7ea.svg +0 -1
  95. package/dist/assets/img/loader.37000a7.svg +0 -1
  96. package/dist/assets/img/loading_static.a27f0ac.svg +0 -10
  97. package/dist/assets/img/main-service1.d536cc2.png +0 -0
  98. package/dist/assets/img/main-service2.9b99549.png +0 -0
  99. package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
  100. package/dist/assets/img/package.8d37d0f.svg +0 -5
  101. package/dist/assets/img/package_fade.763c001.svg +0 -1
  102. package/dist/assets/img/rating--average.1ea492c.svg +0 -12
  103. package/dist/assets/img/rating--great.e3d712e.svg +0 -16
  104. package/dist/assets/img/rating--poor.2938a25.svg +0 -12
  105. package/dist/assets/img/search.f9705ff.svg +0 -1
  106. package/dist/assets/img/send.6db52a9.svg +0 -3
  107. package/dist/assets/img/shop.f7dc7d8.svg +0 -1
  108. package/dist/assets/img/shop_faded.df7845a.svg +0 -1
  109. package/dist/assets/img/stars_v2.79cf728.png +0 -0
  110. package/dist/assets/img/subiz-mono.8fbc067.svg +0 -3
  111. package/dist/assets/img/x.26fdfa3.svg +0 -5
  112. package/dist/malicious-app.js +0 -17
  113. package/dist/screenshoot.html +0 -7
  114. package/dist/screenshoot.js +0 -12630
@@ -412,15 +412,15 @@ a.message_error {
412
412
  padding: 10px 18px;
413
413
  display: block;
414
414
  text-align: center;
415
- .color(@link);
415
+ .color(@black);
416
416
  border: 1px solid @black;
417
417
  border-radius: 12px;
418
418
  text-overflow: ellipsis;
419
419
  overflow: hidden;
420
420
  font-weight: 500;
421
- text-decoration: underline;
422
421
  &:hover {
423
- .color(@link-hover);
422
+ .color(@primary-color);
423
+ border-color: @primary-color;
424
424
  }
425
425
  white-space: nowrap;
426
426
  }
@@ -515,6 +515,11 @@ a.message_error {
515
515
  border: none;
516
516
  border-top: 1px solid #d8d8d8;
517
517
  width: 100%;
518
+ .color(@link);
519
+ &:hover {
520
+ .color(@link-hover);
521
+ border-color: #d8d8d8;
522
+ }
518
523
  }
519
524
  .generic-attachment--element-title {
520
525
  padding: 0px 13px;
@@ -789,8 +794,7 @@ a.product_attachment__title {
789
794
 
790
795
  .message-event-actions {
791
796
  position: absolute;
792
- bottom: -18px;
793
- margin-top: 4px;
797
+ bottom: -10px;
794
798
  opacity: 0.7;
795
799
  left: calc(100% - 25px);
796
800
  display: none;
@@ -798,6 +802,10 @@ a.product_attachment__title {
798
802
  background-color: white;
799
803
  border-radius: 4px;
800
804
  z-index: 10;
805
+
806
+ &.ended {
807
+ bottom: 14px;
808
+ }
801
809
  }
802
810
 
803
811
  .message-event-actions:hover {
@@ -808,13 +816,22 @@ a.product_attachment__title {
808
816
  display: flex;
809
817
  }
810
818
 
819
+ .message-event-actions-static {
820
+ visibility: hidden;
821
+ display: flex;
822
+ margin-top: 2px;
823
+ border: none;
824
+ padding: 0;
825
+ gap: 4px;
826
+ }
827
+
811
828
  .agent-convo-event-inner.last {
812
829
  .message-event-actions {
813
- display: flex;
814
- position: unset;
815
- margin-top: 4px;
816
- border: none;
817
- padding: 0;
830
+ display: none;
831
+ }
832
+
833
+ .message-event-actions-static {
834
+ visibility: visible;
818
835
  }
819
836
 
820
837
  .message-event-action-btn {
@@ -857,7 +874,6 @@ a.product_attachment__title {
857
874
  }
858
875
 
859
876
  .message-event-action-btn {
860
- height: 24px;
861
877
  display: flex;
862
878
  align-items: center;
863
879
  justify-content: center;
@@ -247,7 +247,7 @@
247
247
  justify-content: center;
248
248
  padding-left: 32px;
249
249
  padding-right: 32px;
250
- height: 40px;
250
+ height: 42px;
251
251
  .color(@text-color);
252
252
  font-size: 16px;
253
253
  font-weight: 500;
@@ -16,7 +16,7 @@ function Buttons(props) {
16
16
  href: 'tel:' + button.phone_number,
17
17
  key: index,
18
18
  title: button.title
19
- }, props.t.i18n(button.i18n_title) || button.title);
19
+ }, props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || `${props.t('call')} ${button.phone_number}`);
20
20
  }
21
21
  if (button.type === 'url_button') {
22
22
  return (0, _preact.h)("a", {
@@ -25,7 +25,7 @@ function Buttons(props) {
25
25
  target: "_blank",
26
26
  key: index,
27
27
  title: button.title
28
- }, props.t.i18n(button.i18n_title) || button.title || button.url);
28
+ }, props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || button.url);
29
29
  }
30
30
  if (button.type === 'postback_button') {
31
31
  return (0, _preact.h)("a", {
@@ -58,10 +58,16 @@ class ChatButton extends _common.Com {
58
58
  return;
59
59
  }
60
60
  }
61
- this.props.store.updateLastview({
62
- screen: 'preview',
63
- previewEvent: ev
64
- });
61
+ let accid = _index.default.get(this.props.store.matchAccount(), 'id');
62
+ if (accid === 'acsbdpjwipneldivgwcr') {
63
+ let cid = _index.default.convoOfEv(ev);
64
+ if (cid) this.props.onNewMessageShowWidget && this.props.onNewMessageShowWidget(cid);
65
+ } else {
66
+ this.props.store.updateLastview({
67
+ screen: 'preview',
68
+ previewEvent: ev
69
+ });
70
+ }
65
71
  this.forceUpdate();
66
72
  });
67
73
  this.props.store.onLastview(this, () => {
@@ -126,6 +132,7 @@ class ChatButton extends _common.Com {
126
132
  let byid = greeting.agent_id;
127
133
  if (!byid) byid = randomAgent(agentM).id;
128
134
  let text = this.props.t.i18n(_index.default.get(greeting, 'greeting', {})) || greeting.message;
135
+ if (!text) return {};
129
136
  return {
130
137
  by: {
131
138
  id: byid,
@@ -288,6 +295,7 @@ class ChatButton extends _common.Com {
288
295
  let quickReplies = _index.default.find(attachments, att => att.type === 'quick_replies');
289
296
  quickReplies = _index.default.get(quickReplies, 'quick_replies') || [];
290
297
  quickReplies = _index.default.take(quickReplies, 10);
298
+ if (_index.default.get(accountSetting, 'greeting.hide_quick_replies')) quickReplies = [];
291
299
  let imgAtt = _index.default.find(attachments, att => _index.default.includes(att.mimetype, 'image') && att.url);
292
300
  let uri = _index.default.get(imgAtt, 'url') || '';
293
301
  if (uri && !uri.startsWith('https://') && !uri.startsWith('http://') && !uri.startsWith('content://') && !uri.startsWith('data:')) {
@@ -326,7 +326,7 @@ class Event extends _common.Com {
326
326
  });
327
327
  }
328
328
  let $sender = null;
329
- if (this.props.event.mode === 'lead') $sender = (0, _preact.h)("div", {
329
+ if (this.props.event.mode === 'lead' && _index.default.get(ev, 'by.type') !== 'user') $sender = (0, _preact.h)("div", {
330
330
  class: "pt-3"
331
331
  });
332
332
  let $error = null;
@@ -445,8 +445,22 @@ class Event extends _common.Com {
445
445
  if (hasLike) likecls += ' active';
446
446
  let dislikecls = 'message-event-action-btn';
447
447
  if (hasDislike) dislikecls += ' active';
448
- return (0, _preact.h)("div", {
449
- class: "message-event-actions"
448
+ let actionscls = 'message-event-actions';
449
+ if (_index.default.get(this.props.event, 'is_end')) actionscls += ' ended';
450
+ return (0, _preact.h)(_preact.Fragment, null, (0, _preact.h)("div", {
451
+ class: actionscls
452
+ }, (0, _preact.h)("div", {
453
+ class: likecls,
454
+ onClick: () => this.onSendReaction(hasLike ? 'remove_like' : 'like')
455
+ }, (0, _preact.h)("div", {
456
+ class: "message-event-action-btn-svg like"
457
+ })), (0, _preact.h)("div", {
458
+ class: dislikecls,
459
+ onClick: () => this.onSendReaction(hasDislike ? 'remove_dislike' : 'dislike')
460
+ }, (0, _preact.h)("div", {
461
+ class: "message-event-action-btn-svg dislike"
462
+ }))), _index.default.get(this.props.event, 'is_end') && (0, _preact.h)("div", {
463
+ class: "message-event-actions-static"
450
464
  }, (0, _preact.h)("div", {
451
465
  class: likecls,
452
466
  onClick: () => this.onSendReaction(hasLike ? 'remove_like' : 'like')
@@ -457,10 +471,9 @@ class Event extends _common.Com {
457
471
  onClick: () => this.onSendReaction(hasDislike ? 'remove_dislike' : 'dislike')
458
472
  }, (0, _preact.h)("div", {
459
473
  class: "message-event-action-btn-svg dislike"
460
- })));
474
+ }))));
461
475
  }
462
476
  renderAIDevNote() {
463
- if (!this.props.isLast) return null;
464
477
  if (!this.props.store.isAIDevMode()) return null;
465
478
  let cid = _index.default.get(this.props.event.ev, 'data.message.conversation_id', '');
466
479
  if (cid.startsWith('cslight')) return null;
@@ -473,7 +486,7 @@ class Event extends _common.Com {
473
486
  let dislikecls = 'message-event-action-btn message-event-action-btn__dev message-event-action-btn_dislike';
474
487
  if (hasDislike) dislikecls += ' active';
475
488
  return (0, _preact.h)("div", {
476
- class: "message-event-actions"
489
+ class: "message-event-actions-static"
477
490
  }, (0, _preact.h)("div", {
478
491
  class: likecls,
479
492
  onClick: () => this.onSendReaction(hasLike ? 'remove_like' : 'like')
@@ -130,10 +130,10 @@ class Events extends _common.Com {
130
130
  }
131
131
  }
132
132
  };
133
- events.push(fakeev);
134
133
  processEvents(convo, events);
134
+ events.push(fakeev);
135
135
  let $events = _index.default.map(events, ev => {
136
- let isLast = ev.ev.id === _index.default.get(convo, 'last_message_sent.id');
136
+ let isLast = ev.is_last_message_send;
137
137
  return (0, _preact.h)(_Event.default, {
138
138
  isLast: isLast,
139
139
  chatbox: this.props.chatbox,
@@ -312,17 +312,26 @@ function processEvents(convo, events) {
312
312
  break;
313
313
  }
314
314
  }
315
+ let lastMsgSentIdx = -1;
315
316
  for (var i = 0; i < events.length; i++) {
316
317
  let curEvent = events[i];
317
318
  let prevEvent = events[i - 1];
319
+ let nextEvent = events[i + 1];
318
320
  if (curEvent.ev.type === 'message_sent') {
321
+ lastMsgSentIdx = i;
319
322
  curEvent.mode = 'lead';
320
323
  if (_index.default.get(prevEvent, 'ev.type') === 'message_sent' && _index.default.get(prevEvent, 'ev.by.id') === _index.default.get(curEvent, 'ev.by.id')) {
321
324
  curEvent.mode = 'follow';
322
325
  }
326
+ if (_index.default.get(nextEvent, 'ev.type') !== 'message_sent' || _index.default.get(nextEvent, 'ev.by.id') !== _index.default.get(curEvent, 'ev.by.id')) {
327
+ curEvent.is_end = true;
328
+ }
323
329
  continue;
324
330
  }
325
331
  }
332
+ if (lastMsgSentIdx > -1) {
333
+ events[lastMsgSentIdx].is_last_message_send = true;
334
+ }
326
335
  }
327
336
  function visibleEvent(ev) {
328
337
  let type = _index.default.get(ev, 'type');
@@ -724,7 +724,9 @@ class Widget extends _common.Com {
724
724
  class: "widget-body--content flex-grow-1 pl-3 pr-3 pb-2 d-flex flex-column"
725
725
  }, (0, _preact.h)("div", {
726
726
  class: "mt-2 d-flex flex-column"
727
- }, (0, _preact.h)("div", null, title), this.renderFields(form, formName)), (0, _preact.h)("div", {
727
+ }, (0, _preact.h)("div", null, title), this.renderFields(form, formName)), this.props.store.isMobile() ? (0, _preact.h)("div", {
728
+ style: "height: 20px !important; flex-shrink: 0 !important"
729
+ }) : (0, _preact.h)("div", {
728
730
  style: "min-height: 15px !important; flex: 1 !important; flex-shrink: 0 !important"
729
731
  }), (0, _preact.h)("button", {
730
732
  class: btncls,
@@ -86,6 +86,7 @@ class Main extends _common.Com {
86
86
  ref: this.refButton,
87
87
  isShow: !isShowWidget,
88
88
  onClick: e => this.showWidget(e),
89
+ onNewMessageShowWidget: cid => this.onNewMessageShowWidget(cid),
89
90
  onSelectQuickReply: msg => this.onSelectQuickReply(msg),
90
91
  t: this.props.t
91
92
  }), (0, _preact.h)(_Widget.default, {
@@ -143,6 +144,18 @@ class Main extends _common.Com {
143
144
  this.refWidget.current && this.refWidget.current.sendMessage(message);
144
145
  });
145
146
  }
147
+ onNewMessageShowWidget(cid) {
148
+ if (this.props.store.isMobile()) modifyViewport();
149
+ this.props.store.updateLastview({
150
+ screen: 'widget',
151
+ previewEvent: {},
152
+ view: 'chat',
153
+ opts: {
154
+ cid
155
+ }
156
+ });
157
+ this.forceUpdate();
158
+ }
146
159
  async showWidget(p) {
147
160
  let cid = p.cid;
148
161
  let newView = {
@@ -183,7 +196,8 @@ class Main extends _common.Com {
183
196
  restoreViewport();
184
197
  this.props.store.updateLastview({
185
198
  screen: 'button',
186
- previewEvent: {}
199
+ previewEvent: {},
200
+ minimized: Date.now()
187
201
  });
188
202
  this.forceUpdate();
189
203
  }
@@ -882,7 +882,6 @@ class Store {
882
882
  this.pubsub.publish('events', oldev);
883
883
  }
884
884
  if (ev.type !== 'message_pong' && ev.type !== 'conversation_typing') {
885
- this.chain.put(cid, ev.id, _index.default.getMs(ev.created), ev);
886
885
  if (ev.type === 'message_sent') {
887
886
  let idemkey = _index.default.get(ev, 'data.message.idempotency_key');
888
887
  let found = _index.default.find(this.listEvents(cid), oldev => oldev.id === idemkey);
@@ -892,6 +891,7 @@ class Store {
892
891
  }
893
892
  convo.last_message_sent = ev;
894
893
  }
894
+ this.chain.put(cid, ev.id, _index.default.getMs(ev.created), ev);
895
895
  }
896
896
  this._setConvo(convo);
897
897
  this.pubsub.publish('account');
@@ -148,10 +148,13 @@ function extractLinks(text) {
148
148
  var out = [];
149
149
  var match;
150
150
  while (match = reg.exec(text)) {
151
- out.push({
152
- index: match.index,
153
- length: reg.lastIndex - match.index
154
- });
151
+ const MINIMUM_URL_CHARS = 5;
152
+ if (reg.lastIndex - match.index > MINIMUM_URL_CHARS + 1) {
153
+ out.push({
154
+ index: match.index,
155
+ length: reg.lastIndex - match.index
156
+ });
157
+ }
155
158
  }
156
159
  return out;
157
160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/widget-v4",
3
- "version": "4.1.187",
3
+ "version": "4.1.191",
4
4
  "main": "./compiled_src/lib.js",
5
5
  "scripts": {
6
6
  "dev": "npx webpack serve --config webpack.dev.js",
@@ -22,14 +22,14 @@
22
22
  },
23
23
  "devDependencies": {
24
24
  "@babel/cli": "^7.28.3",
25
- "@babel/core": "^7.28.4",
25
+ "@babel/core": "^7.28.5",
26
26
  "@babel/plugin-proposal-class-properties": "^7.18.6",
27
27
  "@babel/plugin-transform-react-jsx": "^7.27.1",
28
- "@babel/preset-env": "^7.28.3",
28
+ "@babel/preset-env": "^7.28.5",
29
29
  "babel-loader": "^10.0.0",
30
30
  "babel-plugin-syntax-jsx": "^6.18.0",
31
31
  "html-webpack-plugin": "^5.6.4",
32
- "puppeteer": "^24.25.0",
32
+ "puppeteer": "^24.27.0",
33
33
  "webpack": "^5.102.1",
34
34
  "webpack-bundle-analyzer": "^4.10.2",
35
35
  "webpack-cli": "^6.0.1",
@@ -7,7 +7,7 @@ export default function Buttons(props) {
7
7
  if (button.type === 'call_button') {
8
8
  return (
9
9
  <a class='url-button-attachment' href={'tel:' + button.phone_number} key={index} title={button.title}>
10
- {props.t.i18n(button.i18n_title) || button.title}
10
+ {props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || `${props.t('call')} ${button.phone_number}`}
11
11
  </a>
12
12
  )
13
13
  }
@@ -15,7 +15,7 @@ export default function Buttons(props) {
15
15
  if (button.type === 'url_button') {
16
16
  return (
17
17
  <a class='url-button-attachment' href={button.url} target='_blank' key={index} title={button.title}>
18
- {props.t.i18n(button.i18n_title) || button.title || button.url}
18
+ {props.t.i18n(button.i18n_title) || props.t.i18n(button.old_i18n_title) || button.title || button.url}
19
19
  </a>
20
20
  )
21
21
  }
@@ -58,7 +58,15 @@ export default class ChatButton extends Com {
58
58
  }
59
59
  }
60
60
 
61
- this.props.store.updateLastview({screen: 'preview', previewEvent: ev})
61
+ let accid = sb.get(this.props.store.matchAccount(), 'id')
62
+
63
+ // american study request old flow
64
+ if (accid === 'acsbdpjwipneldivgwcr') {
65
+ let cid = sb.convoOfEv(ev)
66
+ if (cid) this.props.onNewMessageShowWidget && this.props.onNewMessageShowWidget(cid)
67
+ } else {
68
+ this.props.store.updateLastview({screen: 'preview', previewEvent: ev})
69
+ }
62
70
  this.forceUpdate()
63
71
  })
64
72
  this.props.store.onLastview(this, () => {
@@ -145,6 +153,7 @@ export default class ChatButton extends Com {
145
153
  if (!byid) byid = randomAgent(agentM).id
146
154
 
147
155
  let text = this.props.t.i18n(sb.get(greeting, 'greeting', {})) || greeting.message
156
+ if (!text) return {} // work for api subiz('overrideChatbox', {greeting; ''})
148
157
  return {
149
158
  by: {id: byid, type: 'agent'},
150
159
  data: {message: {text, format: 'plaintext'}},
@@ -299,6 +308,8 @@ export default class ChatButton extends Com {
299
308
  let quickReplies = sb.find(attachments, (att) => att.type === 'quick_replies')
300
309
  quickReplies = sb.get(quickReplies, 'quick_replies') || []
301
310
  quickReplies = sb.take(quickReplies, 10)
311
+ // dont show with setting greeting.hide_quick_replies
312
+ if (sb.get(accountSetting, 'greeting.hide_quick_replies')) quickReplies = []
302
313
  let imgAtt = sb.find(attachments, (att) => sb.includes(att.mimetype, 'image') && att.url)
303
314
  let uri = sb.get(imgAtt, 'url') || ''
304
315
  if (
@@ -19,7 +19,7 @@ import InfoMessage from './InfoMessage.js' // message by system like convo join,
19
19
  import sb from '../util/index.js'
20
20
  import Time from './time.js'
21
21
  import {Com} from '../common.js'
22
- import {h, createRef} from 'preact'
22
+ import {h, createRef, Fragment} from 'preact'
23
23
 
24
24
  // ['event'],
25
25
  export default class Event extends Com {
@@ -300,7 +300,7 @@ export default class Event extends Com {
300
300
  }
301
301
 
302
302
  let $sender = null
303
- if (this.props.event.mode === 'lead') $sender = <div class='pt-3'></div>
303
+ if (this.props.event.mode === 'lead' && sb.get(ev, 'by.type') !== 'user') $sender = <div class='pt-3'></div>
304
304
 
305
305
  let $error = null
306
306
  if (ev._error) $dot = null
@@ -396,20 +396,35 @@ export default class Event extends Com {
396
396
  if (hasLike) likecls += ' active'
397
397
  let dislikecls = 'message-event-action-btn'
398
398
  if (hasDislike) dislikecls += ' active'
399
+
400
+ let actionscls = 'message-event-actions'
401
+ if (sb.get(this.props.event, 'is_end')) actionscls += ' ended'
402
+
399
403
  return (
400
- <div class='message-event-actions'>
401
- <div class={likecls} onClick={() => this.onSendReaction(hasLike ? 'remove_like' : 'like')}>
402
- <div class='message-event-action-btn-svg like' />
403
- </div>
404
- <div class={dislikecls} onClick={() => this.onSendReaction(hasDislike ? 'remove_dislike' : 'dislike')}>
405
- <div class='message-event-action-btn-svg dislike' />
404
+ <Fragment>
405
+ <div class={actionscls}>
406
+ <div class={likecls} onClick={() => this.onSendReaction(hasLike ? 'remove_like' : 'like')}>
407
+ <div class='message-event-action-btn-svg like' />
408
+ </div>
409
+ <div class={dislikecls} onClick={() => this.onSendReaction(hasDislike ? 'remove_dislike' : 'dislike')}>
410
+ <div class='message-event-action-btn-svg dislike' />
411
+ </div>
406
412
  </div>
407
- </div>
413
+ {sb.get(this.props.event, 'is_end') && (
414
+ <div class='message-event-actions-static'>
415
+ <div class={likecls} onClick={() => this.onSendReaction(hasLike ? 'remove_like' : 'like')}>
416
+ <div class='message-event-action-btn-svg like' />
417
+ </div>
418
+ <div class={dislikecls} onClick={() => this.onSendReaction(hasDislike ? 'remove_dislike' : 'dislike')}>
419
+ <div class='message-event-action-btn-svg dislike' />
420
+ </div>
421
+ </div>
422
+ )}
423
+ </Fragment>
408
424
  )
409
425
  }
410
426
 
411
427
  renderAIDevNote() {
412
- if (!this.props.isLast) return null
413
428
  if (!this.props.store.isAIDevMode()) return null
414
429
  let cid = sb.get(this.props.event.ev, 'data.message.conversation_id', '')
415
430
  if (cid.startsWith('cslight')) return null
@@ -424,7 +439,7 @@ export default class Event extends Com {
424
439
  if (hasDislike) dislikecls += ' active'
425
440
 
426
441
  return (
427
- <div class='message-event-actions'>
442
+ <div class='message-event-actions-static'>
428
443
  <div class={likecls} onClick={() => this.onSendReaction(hasLike ? 'remove_like' : 'like')}>
429
444
  <div class='message-event-action-btn-svg like' /> Good
430
445
  </div>
@@ -124,11 +124,13 @@ export default class Events extends Com {
124
124
  data: {message: {text: '...', conversation_id: this.props.cid}},
125
125
  },
126
126
  }
127
- events.push(fakeev)
127
+
128
128
  processEvents(convo, events)
129
+ // we dont want fakeev cause some unexpected buf when processEvents
130
+ events.push(fakeev)
129
131
 
130
132
  let $events = sb.map(events, (ev) => {
131
- let isLast = ev.ev.id === sb.get(convo, 'last_message_sent.id')
133
+ let isLast = ev.is_last_message_send
132
134
  return (
133
135
  <Event
134
136
  isLast={isLast}
@@ -320,12 +322,16 @@ function processEvents(convo, events) {
320
322
  }
321
323
  }
322
324
 
325
+ let lastMsgSentIdx = -1
323
326
  // insert lead
324
327
  for (var i = 0; i < events.length; i++) {
325
328
  let curEvent = events[i]
326
329
  let prevEvent = events[i - 1]
330
+ let nextEvent = events[i + 1]
327
331
 
328
332
  if (curEvent.ev.type === 'message_sent') {
333
+ // ignore fake typing message_sent event at last
334
+ lastMsgSentIdx = i
329
335
  curEvent.mode = 'lead'
330
336
  if (
331
337
  sb.get(prevEvent, 'ev.type') === 'message_sent' &&
@@ -333,9 +339,18 @@ function processEvents(convo, events) {
333
339
  ) {
334
340
  curEvent.mode = 'follow'
335
341
  }
342
+ if (
343
+ sb.get(nextEvent, 'ev.type') !== 'message_sent' ||
344
+ sb.get(nextEvent, 'ev.by.id') !== sb.get(curEvent, 'ev.by.id')
345
+ ) {
346
+ curEvent.is_end = true
347
+ }
336
348
  continue
337
349
  }
338
350
  }
351
+ if (lastMsgSentIdx > -1) {
352
+ events[lastMsgSentIdx].is_last_message_send = true
353
+ }
339
354
  }
340
355
 
341
356
  function visibleEvent(ev) {
@@ -650,7 +650,11 @@ export default class Widget extends Com {
650
650
  <div>{title}</div>
651
651
  {this.renderFields(form, formName)}
652
652
  </div>
653
- <div style='min-height: 15px !important; flex: 1 !important; flex-shrink: 0 !important'></div>
653
+ {this.props.store.isMobile() ? (
654
+ <div style='height: 20px !important; flex-shrink: 0 !important'></div>
655
+ ) : (
656
+ <div style='min-height: 15px !important; flex: 1 !important; flex-shrink: 0 !important'></div>
657
+ )}
654
658
  <button
655
659
  class={btncls}
656
660
  onClick={(_) => this.submitPrechatForm(form, formName)}
@@ -91,6 +91,7 @@ export default class Main extends Com {
91
91
  ref={this.refButton}
92
92
  isShow={!isShowWidget}
93
93
  onClick={(e) => this.showWidget(e)}
94
+ onNewMessageShowWidget={(cid) => this.onNewMessageShowWidget(cid)}
94
95
  onSelectQuickReply={(msg) => this.onSelectQuickReply(msg)}
95
96
  t={this.props.t}
96
97
  />
@@ -152,6 +153,12 @@ export default class Main extends Com {
152
153
  })
153
154
  }
154
155
 
156
+ onNewMessageShowWidget(cid) {
157
+ if (this.props.store.isMobile()) modifyViewport()
158
+ this.props.store.updateLastview({screen: 'widget', previewEvent: {}, view: 'chat', opts: {cid}})
159
+ this.forceUpdate()
160
+ }
161
+
155
162
  async showWidget(p) {
156
163
  //this.refButton.current && this.refButton.current.ClearPreview()
157
164
 
@@ -189,7 +196,7 @@ export default class Main extends Com {
189
196
 
190
197
  hideWidget() {
191
198
  restoreViewport()
192
- this.props.store.updateLastview({screen: 'button', previewEvent: {}})
199
+ this.props.store.updateLastview({screen: 'button', previewEvent: {}, minimized: Date.now()})
193
200
  this.forceUpdate()
194
201
  }
195
202
 
@@ -1039,7 +1039,6 @@ export default class Store {
1039
1039
 
1040
1040
  // dont store pong and typing
1041
1041
  if (ev.type !== 'message_pong' && ev.type !== 'conversation_typing') {
1042
- this.chain.put(cid, ev.id, sb.getMs(ev.created), ev)
1043
1042
  if (ev.type === 'message_sent') {
1044
1043
  let idemkey = sb.get(ev, 'data.message.idempotency_key')
1045
1044
  let found = sb.find(this.listEvents(cid), (oldev) => oldev.id === idemkey)
@@ -1051,6 +1050,7 @@ export default class Store {
1051
1050
 
1052
1051
  convo.last_message_sent = ev
1053
1052
  }
1053
+ this.chain.put(cid, ev.id, sb.getMs(ev.created), ev)
1054
1054
  }
1055
1055
  this._setConvo(convo)
1056
1056
  this.pubsub.publish('account')
@@ -102,7 +102,10 @@ export function extractLinks(text) {
102
102
  var out = []
103
103
  var match
104
104
  while ((match = reg.exec(text))) {
105
- out.push({index: match.index, length: reg.lastIndex - match.index})
105
+ const MINIMUM_URL_CHARS = 5
106
+ if (reg.lastIndex - match.index > MINIMUM_URL_CHARS + 1) {
107
+ out.push({index: match.index, length: reg.lastIndex - match.index})
108
+ }
106
109
  }
107
110
 
108
111
  return out