@subiz/widget-v4 4.1.178 → 4.1.179
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/less/base.less +28 -0
- package/assets/less/chatbox.less +4 -0
- package/assets/less/message.less +0 -8
- package/assets/less/widget.less +161 -0
- package/compiled_src/chatbox/ChatButton.js +97 -48
- package/compiled_src/chatbox/main.js +39 -52
- package/compiled_src/store/store.js +11 -15
- package/package.json +5 -5
- package/src/chatbox/ChatButton.js +112 -45
- package/src/chatbox/Widget.js +0 -1
- package/src/chatbox/main.js +29 -51
- package/src/store/store.js +20 -13
package/assets/less/base.less
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
@red: #dc3545;
|
|
17
17
|
@yellow: #ffc107;
|
|
18
18
|
@green: #28a745;
|
|
19
|
+
@green-light-bg: #28a74526;
|
|
20
|
+
@border: @gray-300;
|
|
19
21
|
|
|
20
22
|
@link: #0d6efd;
|
|
21
23
|
@link-hover: #024dbc;
|
|
@@ -65,3 +67,29 @@
|
|
|
65
67
|
-moz-mask-image: url(@url);
|
|
66
68
|
mask-image: url(@url);
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
.badge {
|
|
72
|
+
padding: 2px 8px;
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
border-radius: 6px;
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
|
|
79
|
+
&.badge--success {
|
|
80
|
+
.color(@green);
|
|
81
|
+
background: @green-light-bg;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.dot {
|
|
86
|
+
width: 8px;
|
|
87
|
+
height: 8px;
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
flex-shrink: 0;
|
|
90
|
+
background: @black;
|
|
91
|
+
|
|
92
|
+
&.dot--success {
|
|
93
|
+
background: @green;
|
|
94
|
+
}
|
|
95
|
+
}
|
package/assets/less/chatbox.less
CHANGED
|
@@ -92,6 +92,7 @@ body div#sbz92 {
|
|
|
92
92
|
|
|
93
93
|
font-family: @font-family-sans-serif;
|
|
94
94
|
font-size: @font-size-base;
|
|
95
|
+
line-height: 1.25;
|
|
95
96
|
|
|
96
97
|
-webkit-box-sizing: border-box; // Safari/Chrome, other WebKit
|
|
97
98
|
-moz-box-sizing: border-box; // Firefox, other Gecko
|
|
@@ -209,6 +210,9 @@ body div#sbz92 {
|
|
|
209
210
|
.ml-2 {
|
|
210
211
|
margin-left: @spacer2;
|
|
211
212
|
}
|
|
213
|
+
.mr-1 {
|
|
214
|
+
margin-right: @spacer1;
|
|
215
|
+
}
|
|
212
216
|
.mr-2 {
|
|
213
217
|
margin-right: @spacer2;
|
|
214
218
|
}
|
package/assets/less/message.less
CHANGED
|
@@ -507,7 +507,6 @@ a.message_error {
|
|
|
507
507
|
}
|
|
508
508
|
|
|
509
509
|
.url-button-attachment {
|
|
510
|
-
text-decoration: none;
|
|
511
510
|
padding: 10px;
|
|
512
511
|
display: block;
|
|
513
512
|
padding-top: 9px;
|
|
@@ -542,13 +541,6 @@ a.message_error {
|
|
|
542
541
|
|
|
543
542
|
.generic-attachment--element.clickable {
|
|
544
543
|
cursor: pointer;
|
|
545
|
-
.generic-attachment--element-title {
|
|
546
|
-
.color(@link);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
&:hover .generic-attachment--element-title {
|
|
550
|
-
.color(@link-hover);
|
|
551
|
-
}
|
|
552
544
|
}
|
|
553
545
|
|
|
554
546
|
.widget_body__events__error_msg {
|
package/assets/less/widget.less
CHANGED
|
@@ -574,3 +574,164 @@
|
|
|
574
574
|
color: #fff;
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
|
+
|
|
578
|
+
.widget-preview-text-message--header {
|
|
579
|
+
display: flex;
|
|
580
|
+
overflow: hidden;
|
|
581
|
+
align-items: center;
|
|
582
|
+
width: 100%;
|
|
583
|
+
|
|
584
|
+
.widget-preview--avatar {
|
|
585
|
+
width: 24px;
|
|
586
|
+
height: 24px;
|
|
587
|
+
flex-shrink: 0;
|
|
588
|
+
margin-right: 10px;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.widget-preview-text-message--author {
|
|
593
|
+
flex: 1;
|
|
594
|
+
overflow: hidden;
|
|
595
|
+
display: flex;
|
|
596
|
+
align-items: center;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.widget-preview-text-message--author-text {
|
|
600
|
+
text-overflow: ellipsis;
|
|
601
|
+
white-space: nowrap;
|
|
602
|
+
overflow: hidden;
|
|
603
|
+
margin-right: 10px;
|
|
604
|
+
line-height: 1.5;
|
|
605
|
+
.color(@secondary-color);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.widget-preview-text-message--content {
|
|
609
|
+
margin-top: 10px;
|
|
610
|
+
white-space: pre-wrap;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.widget-preview-quick-reply-wrapper {
|
|
614
|
+
z-index: @z-index-3;
|
|
615
|
+
width: 100%;
|
|
616
|
+
margin-bottom: 15px;
|
|
617
|
+
display: flex;
|
|
618
|
+
flex-direction: column;
|
|
619
|
+
align-items: flex-start;
|
|
620
|
+
|
|
621
|
+
&.right {
|
|
622
|
+
align-items: flex-end;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.widget-preview-quick-reply-item {
|
|
627
|
+
border-radius: 20px;
|
|
628
|
+
padding: 8px 20px;
|
|
629
|
+
background: @white;
|
|
630
|
+
border: 1.5px solid;
|
|
631
|
+
border-color: @primary-color;
|
|
632
|
+
.color(@primary-color);
|
|
633
|
+
margin-bottom: 15px;
|
|
634
|
+
cursor: pointer;
|
|
635
|
+
transition: 0.3s ease;
|
|
636
|
+
position: relative;
|
|
637
|
+
|
|
638
|
+
&:last-child {
|
|
639
|
+
margin-bottom: 0;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
&:hover {
|
|
643
|
+
.color(@white);
|
|
644
|
+
background-color: @primary-color;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.widget-preview-image-wrapper {
|
|
649
|
+
z-index: @z-index-3;
|
|
650
|
+
width: 100%;
|
|
651
|
+
margin-bottom: 15px;
|
|
652
|
+
display: flex;
|
|
653
|
+
flex-direction: column;
|
|
654
|
+
align-items: flex-start;
|
|
655
|
+
|
|
656
|
+
&.right {
|
|
657
|
+
align-items: flex-end;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.widget-preview-image-item {
|
|
662
|
+
max-width: 300px;
|
|
663
|
+
border-radius: 15px;
|
|
664
|
+
box-shadow: 0px 5px 30px rgba(0, 0, 0, 0.15);
|
|
665
|
+
border: 1px solid @border;
|
|
666
|
+
overflow: hidden;
|
|
667
|
+
cursor: pointer;
|
|
668
|
+
|
|
669
|
+
img {
|
|
670
|
+
width: 100%;
|
|
671
|
+
max-height: 300px;
|
|
672
|
+
object-fit: cover;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.widget-preview-text-message {
|
|
677
|
+
z-index: @z-index-3;
|
|
678
|
+
background: @white;
|
|
679
|
+
box-shadow: 0px 5px 30px rgba(0, 0, 0, 0.15);
|
|
680
|
+
border: 1px solid @border;
|
|
681
|
+
border-radius: 15px;
|
|
682
|
+
max-width: 100%;
|
|
683
|
+
margin-bottom: 15px;
|
|
684
|
+
padding: 15px 20px;
|
|
685
|
+
positive: relative;
|
|
686
|
+
cursor: pointer;
|
|
687
|
+
|
|
688
|
+
&.right {
|
|
689
|
+
border-bottom-right-radius: 8px;
|
|
690
|
+
}
|
|
691
|
+
&.left {
|
|
692
|
+
border-bottom-left-radius: 8px;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.widget-preview-new-wrapper {
|
|
697
|
+
max-width: 340px;
|
|
698
|
+
position: relative;
|
|
699
|
+
|
|
700
|
+
&.hidden {
|
|
701
|
+
display: none;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
&:hover {
|
|
705
|
+
.widget-preview-x-wrapper {
|
|
706
|
+
display: flex;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.widget-preview--btn-close {
|
|
711
|
+
width: 32px;
|
|
712
|
+
height: 32px;
|
|
713
|
+
background-color: #00000040;
|
|
714
|
+
background-size: 16px 16px;
|
|
715
|
+
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi4yIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXIteCI+PGxpbmUgeDE9IjE4IiB5MT0iNiIgeDI9IjYiIHkyPSIxOCI+PC9saW5lPjxsaW5lIHgxPSI2IiB5MT0iNiIgeDI9IjE4IiB5Mj0iMTgiPjwvbGluZT48L3N2Zz4K');
|
|
716
|
+
|
|
717
|
+
&:hover {
|
|
718
|
+
background-color: #00000066;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.widget-preview-x-wrapper {
|
|
724
|
+
display: none;
|
|
725
|
+
justify-content: flex-start;
|
|
726
|
+
width: calc(100% + 40px);
|
|
727
|
+
position: absolute;
|
|
728
|
+
padding: 15px 20px;
|
|
729
|
+
left: -20px;
|
|
730
|
+
bottom: 100%;
|
|
731
|
+
|
|
732
|
+
&.right {
|
|
733
|
+
justify-content: flex-end;
|
|
734
|
+
left: unset;
|
|
735
|
+
right: -20px;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
@@ -16,9 +16,7 @@ class ChatButton extends _common.Com {
|
|
|
16
16
|
constructor(props) {
|
|
17
17
|
super(props);
|
|
18
18
|
this.setState({
|
|
19
|
-
opacity: 0
|
|
20
|
-
previewEvent: {},
|
|
21
|
-
displayPreview: false
|
|
19
|
+
opacity: 0
|
|
22
20
|
});
|
|
23
21
|
this.loadGreeting();
|
|
24
22
|
this.props.store.onUpdate(this, _ => this.forceUpdate());
|
|
@@ -41,10 +39,22 @@ class ChatButton extends _common.Com {
|
|
|
41
39
|
let message = _index.default.get(ev, 'data.message.text') || '';
|
|
42
40
|
if (!message && isquickreplies) return;
|
|
43
41
|
}
|
|
44
|
-
this.
|
|
45
|
-
|
|
42
|
+
let screen = _index.default.get(this.props.store.matchLastview(), 'screen');
|
|
43
|
+
let minimized = _index.default.get(this.props.store.matchLastview(), 'minimized');
|
|
44
|
+
if (screen === 'widget') return;
|
|
45
|
+
if (minimized && Date.now() - minimized < Ms30Mins) return;
|
|
46
|
+
if (this.props.store.isMobile()) {
|
|
47
|
+
this.props.store.updateLastview({
|
|
48
|
+
previewEvent: ev
|
|
49
|
+
});
|
|
50
|
+
this.forceUpdate();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.props.store.updateLastview({
|
|
54
|
+
screen: 'preview',
|
|
46
55
|
previewEvent: ev
|
|
47
56
|
});
|
|
57
|
+
this.forceUpdate();
|
|
48
58
|
});
|
|
49
59
|
}
|
|
50
60
|
fixMissingSetting(chatbox) {
|
|
@@ -84,16 +94,6 @@ class ChatButton extends _common.Com {
|
|
|
84
94
|
style: 'opacity: ' + opacity + ' !important'
|
|
85
95
|
}, this.renderPreview(), this.renderButton());
|
|
86
96
|
}
|
|
87
|
-
ClearPreview() {
|
|
88
|
-
this.setState({
|
|
89
|
-
previewEvent: {}
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
ClosePreview() {
|
|
93
|
-
this.setState({
|
|
94
|
-
displayPreview: false
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
97
|
pickBestGreeting() {
|
|
98
98
|
let convoM = this.props.store.matchConvo('*');
|
|
99
99
|
let unseenConvo = _index.default.filter(convoM, convo => {
|
|
@@ -126,31 +126,47 @@ class ChatButton extends _common.Com {
|
|
|
126
126
|
return unseenConvo[0].last_message_sent;
|
|
127
127
|
}
|
|
128
128
|
ShowGreeting() {
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
this.props.store.updateLastview({
|
|
130
|
+
screen: 'preview',
|
|
131
|
+
previewEvent: this.pickBestGreeting()
|
|
132
132
|
});
|
|
133
|
+
this.forceUpdate();
|
|
133
134
|
}
|
|
134
135
|
HideGreeting() {
|
|
135
|
-
this.
|
|
136
|
+
this.props.store.updateLastview({
|
|
137
|
+
screen: 'button',
|
|
138
|
+
minimized: Date.now(),
|
|
136
139
|
previewEvent: {}
|
|
137
140
|
});
|
|
141
|
+
this.forceUpdate();
|
|
138
142
|
}
|
|
139
143
|
loadGreeting() {
|
|
144
|
+
let minimized = _index.default.get(this.props.store.matchLastview(), 'minimized');
|
|
145
|
+
let screen = _index.default.get(this.props.store.matchLastview(), 'screen');
|
|
146
|
+
console.log('loadGreeting matchLastview', this.props.store.matchLastview());
|
|
147
|
+
if (screen === 'widget') return;
|
|
148
|
+
if (minimized && Date.now() - minimized < Ms30Mins) return;
|
|
140
149
|
let accountSetting = this.props.plugin.chatbox;
|
|
141
|
-
if (new _index.default.Date().getTime() - this.props.store.matchClosePreviewAt() < Ms30Mins) return;
|
|
142
150
|
let greeting = _index.default.get(accountSetting, 'greeting', {});
|
|
143
151
|
let text = this.props.t.i18n(_index.default.get(greeting, 'greeting', {})) || greeting.message;
|
|
144
152
|
let enabled = greeting.enabled;
|
|
145
153
|
if (this.props.store.isMobile()) {
|
|
146
154
|
enabled = enabled && !_index.default.get(greeting, 'mobile_disabled');
|
|
155
|
+
this.props.store.updateLastview({
|
|
156
|
+
screen: 'button',
|
|
157
|
+
previewEvent: {}
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
147
160
|
}
|
|
148
161
|
if (!text || !enabled) {
|
|
149
|
-
this.
|
|
162
|
+
this.props.store.updateLastview({
|
|
163
|
+
screen: 'button',
|
|
150
164
|
previewEvent: {}
|
|
151
165
|
});
|
|
166
|
+
this.forceUpdate();
|
|
152
167
|
return;
|
|
153
168
|
}
|
|
169
|
+
console.log('loadGreeting pickBestGreeting', this.pickBestGreeting());
|
|
154
170
|
this.ShowGreeting();
|
|
155
171
|
}
|
|
156
172
|
onClick() {
|
|
@@ -168,14 +184,14 @@ class ChatButton extends _common.Com {
|
|
|
168
184
|
return this.onPreviewClick();
|
|
169
185
|
}
|
|
170
186
|
onPreviewClick(e) {
|
|
171
|
-
let
|
|
187
|
+
let previewEvent = _index.default.get(this.props.store.matchLastview(), 'previewEvent') || {};
|
|
188
|
+
let cid = _index.default.convoOfEv(previewEvent);
|
|
172
189
|
if (!cid) {
|
|
173
190
|
let convos = _index.default.map(this.props.store.matchConvo('*'));
|
|
174
191
|
let convo = _index.default.find(convos, convo => !_index.default.isConvoSeen(convo, this.props.store.matchUser().id));
|
|
175
192
|
if (!convo) convo = convos[0] || {};
|
|
176
193
|
cid = convo.id;
|
|
177
194
|
}
|
|
178
|
-
this.closePreview(e);
|
|
179
195
|
this.props.onClick && this.props.onClick({
|
|
180
196
|
view: 'chat',
|
|
181
197
|
cid
|
|
@@ -192,7 +208,8 @@ class ChatButton extends _common.Com {
|
|
|
192
208
|
let account = this.props.store.matchAccount();
|
|
193
209
|
if (!account) return null;
|
|
194
210
|
let accountSetting = this.props.plugin.chatbox;
|
|
195
|
-
let
|
|
211
|
+
let previewEvent = _index.default.get(this.props.store.matchLastview(), 'previewEvent') || {};
|
|
212
|
+
let byid = _index.default.get(previewEvent, 'by.display_id', _index.default.get(previewEvent, 'by.id'));
|
|
196
213
|
let agent = this.props.store.matchAgent(byid);
|
|
197
214
|
if (!agent) agent = this.props.store.matchAgent('*')[byid] || {};
|
|
198
215
|
agent = _index.default.cloneDeep(agent);
|
|
@@ -208,14 +225,28 @@ class ChatButton extends _common.Com {
|
|
|
208
225
|
fullname: account.name || this.props.t('agent')
|
|
209
226
|
});
|
|
210
227
|
}
|
|
211
|
-
let
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
228
|
+
let tags = this.renderMessagePreview(previewEvent);
|
|
229
|
+
let attachments = _index.default.get(previewEvent, 'data.message.attachments') || [];
|
|
230
|
+
let quickReplies = _index.default.find(attachments, att => att.type === 'quick_replies');
|
|
231
|
+
quickReplies = _index.default.get(quickReplies, 'quick_replies') || [];
|
|
232
|
+
let imgAtt = _index.default.find(attachments, att => _index.default.includes(att.mimetype, 'image') && att.url);
|
|
233
|
+
let uri = _index.default.get(imgAtt, 'url') || '';
|
|
234
|
+
if (uri && !uri.startsWith('https://') && !uri.startsWith('http://') && !uri.startsWith('content://') && !uri.startsWith('data:')) {
|
|
235
|
+
uri = this.props.store.FileURL + uri;
|
|
236
|
+
}
|
|
237
|
+
let isShowPreview = _index.default.get(this.props.store.matchLastview(), 'screen') === 'preview';
|
|
215
238
|
return (0, _preact.h)("div", {
|
|
216
|
-
class:
|
|
239
|
+
class: `widget-preview-new-wrapper ${isShowPreview ? '' : 'hidden'}`
|
|
217
240
|
}, (0, _preact.h)("div", {
|
|
218
|
-
class:
|
|
241
|
+
class: `widget-preview-x-wrapper ${position}`
|
|
242
|
+
}, (0, _preact.h)("div", {
|
|
243
|
+
class: "widget-preview--btn-close",
|
|
244
|
+
onClick: e => this.closePreview(e)
|
|
245
|
+
})), (0, _preact.h)("div", {
|
|
246
|
+
class: `widget-preview-text-message ${position}`,
|
|
247
|
+
onClick: e => this.onPreviewClick(e)
|
|
248
|
+
}, (0, _preact.h)("div", {
|
|
249
|
+
class: "widget-preview-text-message--header"
|
|
219
250
|
}, (0, _preact.h)("img", {
|
|
220
251
|
alt: "widget avatar",
|
|
221
252
|
class: "widget-preview--avatar",
|
|
@@ -223,21 +254,43 @@ class ChatButton extends _common.Com {
|
|
|
223
254
|
onError: ev => this.onProfileError(ev),
|
|
224
255
|
onload: _ => this.onProfileReady()
|
|
225
256
|
}), (0, _preact.h)("div", {
|
|
226
|
-
class: "widget-preview--
|
|
227
|
-
onClick: e => this.onPreviewClick(e)
|
|
257
|
+
class: "widget-preview-text-message--author"
|
|
228
258
|
}, (0, _preact.h)("div", {
|
|
229
|
-
class: "widget-preview--
|
|
230
|
-
}, agent.fullname), (0, _preact.h)("
|
|
231
|
-
class: "
|
|
232
|
-
}, tags)), (0, _preact.h)("div", {
|
|
233
|
-
class: "widget-preview--btn-close",
|
|
234
|
-
onClick: e => this.closePreview(e)
|
|
235
|
-
})), (0, _preact.h)("div", {
|
|
236
|
-
class: "widget-preview--action",
|
|
237
|
-
onClick: e => this.onPreviewClick(e)
|
|
259
|
+
class: "widget-preview-text-message--author-text"
|
|
260
|
+
}, agent.fullname), (0, _preact.h)("div", {
|
|
261
|
+
class: "badge badge--success"
|
|
238
262
|
}, (0, _preact.h)("div", {
|
|
239
|
-
class: "
|
|
240
|
-
},
|
|
263
|
+
class: "dot dot--success mr-1"
|
|
264
|
+
}), 'ONLINE'))), (0, _preact.h)("div", {
|
|
265
|
+
class: "widget-preview-text-message--content"
|
|
266
|
+
}, tags)), uri && (0, _preact.h)("div", {
|
|
267
|
+
class: `widget-preview-image-wrapper ${position}`
|
|
268
|
+
}, (0, _preact.h)("div", {
|
|
269
|
+
class: "widget-preview-image-item",
|
|
270
|
+
onClick: () => this.onPreviewClick()
|
|
271
|
+
}, (0, _preact.h)("img", {
|
|
272
|
+
src: uri
|
|
273
|
+
}))), _index.default.size(quickReplies) > 0 && (0, _preact.h)("div", {
|
|
274
|
+
class: `widget-preview-quick-reply-wrapper ${position}`
|
|
275
|
+
}, _index.default.map(quickReplies, reply => {
|
|
276
|
+
return (0, _preact.h)("div", {
|
|
277
|
+
class: "widget-preview-quick-reply-item",
|
|
278
|
+
onClick: () => {
|
|
279
|
+
this.props.onSelectQuickReply({
|
|
280
|
+
text: reply.title,
|
|
281
|
+
format: 'plaintext',
|
|
282
|
+
conversation_id: _index.default.convoOfEv(previewEvent),
|
|
283
|
+
attachments: [{
|
|
284
|
+
type: 'postback',
|
|
285
|
+
postback: {
|
|
286
|
+
event_id: previewEvent.id,
|
|
287
|
+
payload: reply.payload
|
|
288
|
+
}
|
|
289
|
+
}]
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}, reply.title);
|
|
293
|
+
})));
|
|
241
294
|
}
|
|
242
295
|
onProfileReady() {
|
|
243
296
|
if (this._buttonLoaded) this.setState({
|
|
@@ -402,11 +455,7 @@ class ChatButton extends _common.Com {
|
|
|
402
455
|
e.preventDefault();
|
|
403
456
|
e.stopPropagation();
|
|
404
457
|
}
|
|
405
|
-
this.
|
|
406
|
-
displayPreview: false
|
|
407
|
-
});
|
|
408
|
-
this.props.store.closePreview();
|
|
409
|
-
this.forceUpdate();
|
|
458
|
+
this.HideGreeting();
|
|
410
459
|
}
|
|
411
460
|
}
|
|
412
461
|
exports.default = ChatButton;
|
|
@@ -40,10 +40,7 @@ class Main extends _common.Com {
|
|
|
40
40
|
this.$cssStyleDiv.id = 'subiz-style-for-' + this.props.plugin.id;
|
|
41
41
|
}
|
|
42
42
|
this.setState({
|
|
43
|
-
cssReady: false
|
|
44
|
-
isShowWidget: false,
|
|
45
|
-
widgetView: '',
|
|
46
|
-
widgetConvoId: ''
|
|
43
|
+
cssReady: false
|
|
47
44
|
});
|
|
48
45
|
this.checkExpand();
|
|
49
46
|
this.props.store.onResetCSS(this, () => this.refreshCSS());
|
|
@@ -59,15 +56,6 @@ class Main extends _common.Com {
|
|
|
59
56
|
this.setState({
|
|
60
57
|
cssReady: true
|
|
61
58
|
});
|
|
62
|
-
if (this.props.store.matchIsOpen() && this.props.store.matchLastview().view) {
|
|
63
|
-
if (this.props.store.isMobile()) return;
|
|
64
|
-
this.showWidget(Object.assign({}, this.props.store.matchLastview().opts, {
|
|
65
|
-
view: this.props.store.matchLastview().view
|
|
66
|
-
}));
|
|
67
|
-
} else {
|
|
68
|
-
restoreViewport();
|
|
69
|
-
if (!this.state.isShowWidget) this.hideWidget();
|
|
70
|
-
}
|
|
71
59
|
}
|
|
72
60
|
render() {
|
|
73
61
|
if (!this.state.cssReady) {
|
|
@@ -83,6 +71,10 @@ class Main extends _common.Com {
|
|
|
83
71
|
return null;
|
|
84
72
|
}
|
|
85
73
|
if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_main = _index.default.Date.now();
|
|
74
|
+
let lastview = this.props.store.matchLastview() || {};
|
|
75
|
+
let isShowWidget = lastview.screen === 'widget';
|
|
76
|
+
let widgetView = lastview.view;
|
|
77
|
+
let widgetConvoId = _index.default.get(lastview, 'opts.cid');
|
|
86
78
|
return (0, _preact.h)("div", {
|
|
87
79
|
class: this.props.store.isMobile() ? 'mobile' : 'desktop'
|
|
88
80
|
}, (0, _preact.h)(_ChatButton.default, {
|
|
@@ -90,15 +82,16 @@ class Main extends _common.Com {
|
|
|
90
82
|
store: this.props.store,
|
|
91
83
|
key: "chat_button",
|
|
92
84
|
ref: this.refButton,
|
|
93
|
-
isShow: !
|
|
85
|
+
isShow: !isShowWidget,
|
|
94
86
|
onClick: e => this.showWidget(e),
|
|
87
|
+
onSelectQuickReply: msg => this.onSelectQuickReply(msg),
|
|
95
88
|
t: this.props.t
|
|
96
89
|
}), (0, _preact.h)(_Widget.default, {
|
|
97
90
|
plugin: this.props.plugin,
|
|
98
91
|
store: this.props.store,
|
|
99
|
-
view:
|
|
100
|
-
cid:
|
|
101
|
-
isShow:
|
|
92
|
+
view: widgetView,
|
|
93
|
+
cid: widgetConvoId,
|
|
94
|
+
isShow: isShowWidget,
|
|
102
95
|
onClose: a => this.onWidgetClose(a),
|
|
103
96
|
onGo: a => this.showWidget(a),
|
|
104
97
|
t: this.props.t,
|
|
@@ -114,7 +107,8 @@ class Main extends _common.Com {
|
|
|
114
107
|
if (!$widget) return;
|
|
115
108
|
if ($widget.wasFormInputed) return;
|
|
116
109
|
if (ev.type !== 'message_sent') return;
|
|
117
|
-
|
|
110
|
+
let isShowWidget = _index.default.get(this.props.store.matchLastview(), 'screen') === 'widget';
|
|
111
|
+
if (!isShowWidget) return;
|
|
118
112
|
let byType = _index.default.get(ev, 'by.type');
|
|
119
113
|
let byid = _index.default.get(ev, 'by.id') || '';
|
|
120
114
|
if (!byid.startsWith('bb') || byType !== 'agent') return;
|
|
@@ -128,49 +122,44 @@ class Main extends _common.Com {
|
|
|
128
122
|
checkExpand() {
|
|
129
123
|
if (this.props.store.isMobile()) return;
|
|
130
124
|
if (this.props.plugin._no_auto_expand) return;
|
|
131
|
-
|
|
125
|
+
return;
|
|
132
126
|
let convoM = this.props.store.matchConvo('*');
|
|
133
127
|
let redconvo = _index.default.find(convoM, convo => !_index.default.isConvoSeen(convo, this.props.store.matchUser().id));
|
|
134
128
|
if (!redconvo || !redconvo.id) return;
|
|
135
|
-
|
|
129
|
+
let isShowWidget = _index.default.get(this.props.store.matchLastview(), 'screen') === 'widget';
|
|
130
|
+
if (!isShowWidget) this.showWidget({
|
|
136
131
|
view: 'chat',
|
|
137
132
|
cid: redconvo.id
|
|
138
133
|
});
|
|
139
134
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
onSelectQuickReply(message) {
|
|
136
|
+
this.showWidget({
|
|
137
|
+
view: 'chat',
|
|
138
|
+
cid: message.conversation_id
|
|
139
|
+
});
|
|
140
|
+
this.forceUpdate(() => {
|
|
141
|
+
this.refWidget.current && this.refWidget.current.sendMessage(message);
|
|
142
|
+
});
|
|
146
143
|
}
|
|
147
144
|
async showWidget(p) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
p.
|
|
153
|
-
}
|
|
154
|
-
p = p || {};
|
|
145
|
+
let cid = p.cid;
|
|
146
|
+
let newView = {
|
|
147
|
+
screen: 'widget',
|
|
148
|
+
minimized: 0,
|
|
149
|
+
view: p.view
|
|
150
|
+
};
|
|
155
151
|
if (!p.view && !p.cid) {
|
|
156
152
|
let convoM = this.props.store.matchConvo('*');
|
|
157
153
|
let redconvo = _index.default.find(convoM, convo => !_index.default.isConvoSeen(convo, this.props.store.matchUser().id));
|
|
158
|
-
|
|
159
|
-
|
|
154
|
+
cid = _index.default.get(redconvo, 'id', _index.default.get(convoM, '0.id'));
|
|
155
|
+
newView.view = 'chat';
|
|
160
156
|
}
|
|
157
|
+
if (cid) newView.opts = {
|
|
158
|
+
cid
|
|
159
|
+
};
|
|
161
160
|
if (this.props.store.isMobile()) modifyViewport();
|
|
162
|
-
this.
|
|
163
|
-
widgetConvoId: p.cid,
|
|
164
|
-
widgetView: p.view
|
|
165
|
-
});
|
|
166
|
-
this.props.store.setIsOpen(true);
|
|
161
|
+
this.props.store.updateLastview(newView);
|
|
167
162
|
this.forceUpdate();
|
|
168
|
-
this.setState({
|
|
169
|
-
isShowWidget: true
|
|
170
|
-
});
|
|
171
|
-
this.props.store.setLastview(p.view, {
|
|
172
|
-
cid: p.cid
|
|
173
|
-
});
|
|
174
163
|
}
|
|
175
164
|
applyMessage(text) {
|
|
176
165
|
this.refWidget.current && this.refWidget.current.applyMessage(text);
|
|
@@ -186,15 +175,13 @@ class Main extends _common.Com {
|
|
|
186
175
|
}
|
|
187
176
|
hideWidget() {
|
|
188
177
|
restoreViewport();
|
|
189
|
-
this.props.store.
|
|
190
|
-
|
|
191
|
-
|
|
178
|
+
this.props.store.updateLastview({
|
|
179
|
+
screen: 'button',
|
|
180
|
+
previewEvent: {}
|
|
192
181
|
});
|
|
182
|
+
this.forceUpdate();
|
|
193
183
|
}
|
|
194
184
|
onWidgetClose() {
|
|
195
|
-
this.refButton.current && this.refButton.current.ClearPreview();
|
|
196
|
-
this.refButton.current && this.refButton.current.ClosePreview();
|
|
197
|
-
this.props.store.setHasManuallyClosed();
|
|
198
185
|
this.hideWidget();
|
|
199
186
|
this.props.store.emitCloseWidgetEvent();
|
|
200
187
|
}
|
|
@@ -139,10 +139,12 @@ class Store {
|
|
|
139
139
|
let user = this.cache.match('user') || {};
|
|
140
140
|
if (!user.id) return {};
|
|
141
141
|
if (lastView.user_id != user.id) return {};
|
|
142
|
+
if (lastView.view && !lastView.screen) {
|
|
143
|
+
lastView.screen = 'widget';
|
|
144
|
+
}
|
|
142
145
|
return lastView;
|
|
143
146
|
});
|
|
144
147
|
_defineProperty(this, "matchIsOpen", () => !!this.kv.match('isopen'));
|
|
145
|
-
_defineProperty(this, "matchHasManuallyClosed", () => !!this.kv.match('hasManuallyClosed'));
|
|
146
148
|
_defineProperty(this, "matchClosePreviewAt", () => this.kv.match('close_preview_at') || 0);
|
|
147
149
|
_defineProperty(this, "checkFormToken", (accid, token) => this.api.checkFormToken(accid, token));
|
|
148
150
|
_defineProperty(this, "submitForm2", (accid, token, data) => this.api.submitForm2(accid, token, data));
|
|
@@ -176,23 +178,17 @@ class Store {
|
|
|
176
178
|
_defineProperty(this, "onConnection", (o, cb) => this.pubsub.on2(o, 'connection', cb));
|
|
177
179
|
_defineProperty(this, "onResetCSS", (o, cb) => this.pubsub.on2(o, 'resetCSS', cb));
|
|
178
180
|
_defineProperty(this, "onHighlight", (o, cb) => this.pubsub.on2(o, 'highlight', cb));
|
|
179
|
-
_defineProperty(this, "setHasManuallyClosed", () => this.kv.put('hasManuallyClosed', true));
|
|
180
|
-
_defineProperty(this, "setIsOpen", isopen => {
|
|
181
|
-
let lastisopen = this.kv.match('isopen');
|
|
182
|
-
this.kv.put('isopen', isopen);
|
|
183
|
-
if (!lastisopen && isopen) {
|
|
184
|
-
sendEventToThirdParty('SUBIZ Chat', 'Opened', 'Subiz Windows');
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
181
|
_defineProperty(this, "closePreview", () => this.kv.put('close_preview_at', new _index.default.Date().getTime()));
|
|
188
|
-
_defineProperty(this, "
|
|
182
|
+
_defineProperty(this, "updateLastview", obj => {
|
|
189
183
|
let user = this.cache.match('user') || {};
|
|
190
184
|
if (!user.id) return;
|
|
191
|
-
this.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
185
|
+
let lastview = this.matchLastview() || {};
|
|
186
|
+
lastview = {
|
|
187
|
+
...lastview,
|
|
188
|
+
...obj,
|
|
189
|
+
user_id: user.id
|
|
190
|
+
};
|
|
191
|
+
this.kv.put('lastview', lastview);
|
|
196
192
|
});
|
|
197
193
|
_defineProperty(this, "timeDiff", 0);
|
|
198
194
|
this.connectionStatus = 'active';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subiz/widget-v4",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.179",
|
|
4
4
|
"main": "./compiled_src/lib.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "npx webpack serve --config webpack.dev.js",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"@subiz/flow": "^1.1.0",
|
|
14
14
|
"@subiz/wsclient": "^4.0.34",
|
|
15
15
|
"cookie_js": "1.4.2",
|
|
16
|
-
"core-js": "^3.
|
|
16
|
+
"core-js": "^3.46.0",
|
|
17
17
|
"css-loader": "5.2.7",
|
|
18
18
|
"file-loader": "^6.2.0",
|
|
19
|
-
"less": "^4.4.
|
|
19
|
+
"less": "^4.4.2",
|
|
20
20
|
"less-loader": "^12.3.0",
|
|
21
21
|
"preact": "10.19.3"
|
|
22
22
|
},
|
|
@@ -29,8 +29,8 @@
|
|
|
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.
|
|
33
|
-
"webpack": "^5.
|
|
32
|
+
"puppeteer": "^24.24.0",
|
|
33
|
+
"webpack": "^5.102.1",
|
|
34
34
|
"webpack-bundle-analyzer": "^4.10.2",
|
|
35
35
|
"webpack-cli": "^6.0.1",
|
|
36
36
|
"webpack-dev-server": "^5.2.2"
|
|
@@ -11,8 +11,6 @@ export default class ChatButton extends Com {
|
|
|
11
11
|
super(props)
|
|
12
12
|
this.setState({
|
|
13
13
|
opacity: 0, // wait for image to load first before setting opacity to 1
|
|
14
|
-
previewEvent: {},
|
|
15
|
-
displayPreview: false,
|
|
16
14
|
})
|
|
17
15
|
this.loadGreeting()
|
|
18
16
|
|
|
@@ -39,8 +37,21 @@ export default class ChatButton extends Com {
|
|
|
39
37
|
let message = sb.get(ev, 'data.message.text') || ''
|
|
40
38
|
if (!message && isquickreplies) return
|
|
41
39
|
}
|
|
40
|
+
let screen = sb.get(this.props.store.matchLastview(), 'screen')
|
|
41
|
+
let minimized = sb.get(this.props.store.matchLastview(), 'minimized')
|
|
42
|
+
if (screen === 'widget') return
|
|
43
|
+
if (minimized && Date.now() - minimized < Ms30Mins) return
|
|
42
44
|
|
|
43
|
-
this.
|
|
45
|
+
if (this.props.store.isMobile()) {
|
|
46
|
+
// dont show greeting fro mobile anymore
|
|
47
|
+
// need setState previewEvent for display 1 unread in mobile
|
|
48
|
+
this.props.store.updateLastview({previewEvent: ev})
|
|
49
|
+
this.forceUpdate()
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.props.store.updateLastview({screen: 'preview', previewEvent: ev})
|
|
54
|
+
this.forceUpdate()
|
|
44
55
|
})
|
|
45
56
|
}
|
|
46
57
|
|
|
@@ -97,15 +108,6 @@ export default class ChatButton extends Com {
|
|
|
97
108
|
)
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
// this method could be call from the parent
|
|
101
|
-
ClearPreview() {
|
|
102
|
-
this.setState({previewEvent: {}})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
ClosePreview() {
|
|
106
|
-
this.setState({displayPreview: false})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
111
|
pickBestGreeting() {
|
|
110
112
|
let convoM = this.props.store.matchConvo('*')
|
|
111
113
|
let unseenConvo = sb
|
|
@@ -136,20 +138,27 @@ export default class ChatButton extends Com {
|
|
|
136
138
|
|
|
137
139
|
// this method could be call from the parent
|
|
138
140
|
ShowGreeting() {
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
this.props.store.updateLastview({screen: 'preview', previewEvent: this.pickBestGreeting()})
|
|
142
|
+
this.forceUpdate()
|
|
143
|
+
//this.setState({
|
|
144
|
+
//previewEvent: this.pickBestGreeting(),
|
|
145
|
+
//})
|
|
143
146
|
}
|
|
144
147
|
|
|
145
148
|
HideGreeting() {
|
|
146
|
-
this.
|
|
149
|
+
this.props.store.updateLastview({screen: 'button', minimized: Date.now(), previewEvent: {}})
|
|
150
|
+
this.forceUpdate()
|
|
151
|
+
//this.setState({previewEvent: {}})
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
loadGreeting() {
|
|
155
|
+
let minimized = sb.get(this.props.store.matchLastview(), 'minimized')
|
|
156
|
+
let screen = sb.get(this.props.store.matchLastview(), 'screen')
|
|
157
|
+
console.log('loadGreeting matchLastview', this.props.store.matchLastview())
|
|
158
|
+
if (screen !== 'preview') return
|
|
159
|
+
if (minimized && Date.now() - minimized < Ms30Mins) return
|
|
150
160
|
let accountSetting = this.props.plugin.chatbox
|
|
151
161
|
// dont show preview if the user has previously closed it
|
|
152
|
-
if (new sb.Date().getTime() - this.props.store.matchClosePreviewAt() < Ms30Mins) return
|
|
153
162
|
|
|
154
163
|
let greeting = sb.get(accountSetting, 'greeting', {})
|
|
155
164
|
let text = this.props.t.i18n(sb.get(greeting, 'greeting', {})) || greeting.message
|
|
@@ -157,11 +166,16 @@ export default class ChatButton extends Com {
|
|
|
157
166
|
let enabled = greeting.enabled
|
|
158
167
|
if (this.props.store.isMobile()) {
|
|
159
168
|
enabled = enabled && !sb.get(greeting, 'mobile_disabled')
|
|
169
|
+
// dont show greeting fro mobile anymore
|
|
170
|
+
this.props.store.updateLastview({screen: 'button', previewEvent: {}})
|
|
171
|
+
return
|
|
160
172
|
}
|
|
161
173
|
if (!text || !enabled) {
|
|
162
|
-
this.
|
|
174
|
+
this.props.store.updateLastview({screen: 'button', previewEvent: {}})
|
|
175
|
+
this.forceUpdate()
|
|
163
176
|
return
|
|
164
177
|
}
|
|
178
|
+
console.log('loadGreeting pickBestGreeting', this.pickBestGreeting())
|
|
165
179
|
this.ShowGreeting()
|
|
166
180
|
}
|
|
167
181
|
|
|
@@ -184,14 +198,15 @@ export default class ChatButton extends Com {
|
|
|
184
198
|
}
|
|
185
199
|
|
|
186
200
|
onPreviewClick(e) {
|
|
187
|
-
let
|
|
201
|
+
let previewEvent = sb.get(this.props.store.matchLastview(), 'previewEvent') || {}
|
|
202
|
+
let cid = sb.convoOfEv(previewEvent)
|
|
188
203
|
if (!cid) {
|
|
189
204
|
let convos = sb.map(this.props.store.matchConvo('*'))
|
|
190
205
|
let convo = sb.find(convos, (convo) => !sb.isConvoSeen(convo, this.props.store.matchUser().id))
|
|
191
206
|
if (!convo) convo = convos[0] || {}
|
|
192
207
|
cid = convo.id
|
|
193
208
|
}
|
|
194
|
-
this.
|
|
209
|
+
//this.HideGreeting()
|
|
195
210
|
this.props.onClick && this.props.onClick({view: 'chat', cid})
|
|
196
211
|
}
|
|
197
212
|
|
|
@@ -205,7 +220,8 @@ export default class ChatButton extends Com {
|
|
|
205
220
|
let account = this.props.store.matchAccount()
|
|
206
221
|
if (!account) return null
|
|
207
222
|
let accountSetting = this.props.plugin.chatbox
|
|
208
|
-
let
|
|
223
|
+
let previewEvent = sb.get(this.props.store.matchLastview(), 'previewEvent') || {}
|
|
224
|
+
let byid = sb.get(previewEvent, 'by.display_id', sb.get(previewEvent, 'by.id'))
|
|
209
225
|
// let agent = sb.cloneDeep(this.props.store.matchAgent(byid)) || {}
|
|
210
226
|
// somehow store.matchAgent(id) return undefined so we try to backup with store.matchAgent('*')[id]
|
|
211
227
|
let agent = this.props.store.matchAgent(byid)
|
|
@@ -225,32 +241,85 @@ export default class ChatButton extends Com {
|
|
|
225
241
|
})
|
|
226
242
|
}
|
|
227
243
|
|
|
228
|
-
let
|
|
229
|
-
|
|
244
|
+
let tags = this.renderMessagePreview(previewEvent)
|
|
245
|
+
let attachments = sb.get(previewEvent, 'data.message.attachments') || []
|
|
246
|
+
let quickReplies = sb.find(attachments, (att) => att.type === 'quick_replies')
|
|
247
|
+
quickReplies = sb.get(quickReplies, 'quick_replies') || []
|
|
248
|
+
let imgAtt = sb.find(attachments, (att) => sb.includes(att.mimetype, 'image') && att.url)
|
|
249
|
+
let uri = sb.get(imgAtt, 'url') || ''
|
|
250
|
+
if (
|
|
251
|
+
uri &&
|
|
252
|
+
!uri.startsWith('https://') &&
|
|
253
|
+
!uri.startsWith('http://') &&
|
|
254
|
+
!uri.startsWith('content://') &&
|
|
255
|
+
!uri.startsWith('data:')
|
|
256
|
+
) {
|
|
257
|
+
uri = this.props.store.FileURL + uri
|
|
258
|
+
}
|
|
230
259
|
|
|
231
|
-
|
|
232
|
-
if (sb.size(tags) === 0) cls += ' widget-preview--hidden'
|
|
260
|
+
let isShowPreview = sb.get(this.props.store.matchLastview(), 'screen') === 'preview'
|
|
233
261
|
|
|
234
262
|
return (
|
|
235
|
-
<div class={
|
|
236
|
-
<div class=
|
|
237
|
-
<img
|
|
238
|
-
alt='widget avatar'
|
|
239
|
-
class='widget-preview--avatar'
|
|
240
|
-
src={this.props.store.replaceFileUrl(agent.avatar_url)}
|
|
241
|
-
onError={(ev) => this.onProfileError(ev)}
|
|
242
|
-
onload={(_) => this.onProfileReady()}
|
|
243
|
-
/>
|
|
244
|
-
<div class='widget-preview--content' onClick={(e) => this.onPreviewClick(e)}>
|
|
245
|
-
<div class='widget-preview--title'>{agent.fullname}</div>
|
|
246
|
-
<p class='widget-preview--message'>{tags}</p>
|
|
247
|
-
</div>
|
|
263
|
+
<div class={`widget-preview-new-wrapper ${isShowPreview ? '' : 'hidden'}`}>
|
|
264
|
+
<div class={`widget-preview-x-wrapper ${position}`}>
|
|
248
265
|
<div class='widget-preview--btn-close' onClick={(e) => this.closePreview(e)} />
|
|
249
266
|
</div>
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
267
|
+
<div class={`widget-preview-text-message ${position}`} onClick={(e) => this.onPreviewClick(e)}>
|
|
268
|
+
<div class='widget-preview-text-message--header'>
|
|
269
|
+
<img
|
|
270
|
+
alt='widget avatar'
|
|
271
|
+
class='widget-preview--avatar'
|
|
272
|
+
src={this.props.store.replaceFileUrl(agent.avatar_url)}
|
|
273
|
+
onError={(ev) => this.onProfileError(ev)}
|
|
274
|
+
onload={(_) => this.onProfileReady()}
|
|
275
|
+
/>
|
|
276
|
+
<div class='widget-preview-text-message--author'>
|
|
277
|
+
<div class='widget-preview-text-message--author-text'>{agent.fullname}</div>
|
|
278
|
+
<div class='badge badge--success'>
|
|
279
|
+
<div class='dot dot--success mr-1' />
|
|
280
|
+
{'ONLINE'}
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
<div class='widget-preview-text-message--content'>{tags}</div>
|
|
253
285
|
</div>
|
|
286
|
+
{uri && (
|
|
287
|
+
<div class={`widget-preview-image-wrapper ${position}`}>
|
|
288
|
+
<div class='widget-preview-image-item' onClick={() => this.onPreviewClick()}>
|
|
289
|
+
<img src={uri} />
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
)}
|
|
293
|
+
{sb.size(quickReplies) > 0 && (
|
|
294
|
+
<div class={`widget-preview-quick-reply-wrapper ${position}`}>
|
|
295
|
+
{sb.map(quickReplies, (reply) => {
|
|
296
|
+
return (
|
|
297
|
+
<div
|
|
298
|
+
class='widget-preview-quick-reply-item'
|
|
299
|
+
onClick={() => {
|
|
300
|
+
// copy chooseQuickReply function from Event.js
|
|
301
|
+
this.props.onSelectQuickReply({
|
|
302
|
+
text: reply.title,
|
|
303
|
+
format: 'plaintext',
|
|
304
|
+
conversation_id: sb.convoOfEv(previewEvent),
|
|
305
|
+
attachments: [
|
|
306
|
+
{
|
|
307
|
+
type: 'postback',
|
|
308
|
+
postback: {
|
|
309
|
+
event_id: previewEvent.id,
|
|
310
|
+
payload: reply.payload,
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
})
|
|
315
|
+
}}
|
|
316
|
+
>
|
|
317
|
+
{reply.title}
|
|
318
|
+
</div>
|
|
319
|
+
)
|
|
320
|
+
})}
|
|
321
|
+
</div>
|
|
322
|
+
)}
|
|
254
323
|
</div>
|
|
255
324
|
)
|
|
256
325
|
}
|
|
@@ -440,9 +509,7 @@ export default class ChatButton extends Com {
|
|
|
440
509
|
e.preventDefault()
|
|
441
510
|
e.stopPropagation()
|
|
442
511
|
}
|
|
443
|
-
this.
|
|
444
|
-
this.props.store.closePreview()
|
|
445
|
-
this.forceUpdate()
|
|
512
|
+
this.HideGreeting()
|
|
446
513
|
}
|
|
447
514
|
}
|
|
448
515
|
|
package/src/chatbox/Widget.js
CHANGED
|
@@ -63,7 +63,6 @@ export default class Widget extends Com {
|
|
|
63
63
|
if (prevProp.cid !== this.props.cid) {
|
|
64
64
|
this.closeOrder()
|
|
65
65
|
this.setState({clickedJoin: false, quickReplyMessage: {}})
|
|
66
|
-
// this.props.store.setLastview('chat', { cid: this.props.cid })
|
|
67
66
|
sb.setTimeout(() => {
|
|
68
67
|
// focus Events then focus MessageInput
|
|
69
68
|
// if there is any pending form, MessageInput will be disabled
|
package/src/chatbox/main.js
CHANGED
|
@@ -45,9 +45,6 @@ export default class Main extends Com {
|
|
|
45
45
|
|
|
46
46
|
this.setState({
|
|
47
47
|
cssReady: false,
|
|
48
|
-
isShowWidget: false,
|
|
49
|
-
widgetView: '',
|
|
50
|
-
widgetConvoId: '',
|
|
51
48
|
})
|
|
52
49
|
|
|
53
50
|
this.checkExpand()
|
|
@@ -62,16 +59,6 @@ export default class Main extends Com {
|
|
|
62
59
|
})
|
|
63
60
|
this.refreshCSS()
|
|
64
61
|
this.setState({cssReady: true})
|
|
65
|
-
|
|
66
|
-
if (this.props.store.matchIsOpen() && this.props.store.matchLastview().view) {
|
|
67
|
-
if (this.props.store.isMobile()) return // dont auto expand widget on mobile
|
|
68
|
-
this.showWidget(
|
|
69
|
-
Object.assign({}, this.props.store.matchLastview().opts, {view: this.props.store.matchLastview().view}),
|
|
70
|
-
)
|
|
71
|
-
} else {
|
|
72
|
-
restoreViewport()
|
|
73
|
-
if (!this.state.isShowWidget) this.hideWidget()
|
|
74
|
-
}
|
|
75
62
|
}
|
|
76
63
|
|
|
77
64
|
render() {
|
|
@@ -88,6 +75,11 @@ export default class Main extends Com {
|
|
|
88
75
|
return null
|
|
89
76
|
}
|
|
90
77
|
if (typeof sbz_info != 'undefined') sbz_info.render_chatbox_main = sb.Date.now()
|
|
78
|
+
let lastview = this.props.store.matchLastview() || {}
|
|
79
|
+
let isShowWidget = lastview.screen === 'widget'
|
|
80
|
+
let widgetView = lastview.view
|
|
81
|
+
let widgetConvoId = sb.get(lastview, 'opts.cid')
|
|
82
|
+
|
|
91
83
|
return (
|
|
92
84
|
<div class={this.props.store.isMobile() ? 'mobile' : 'desktop'}>
|
|
93
85
|
<ChatButton
|
|
@@ -95,16 +87,17 @@ export default class Main extends Com {
|
|
|
95
87
|
store={this.props.store}
|
|
96
88
|
key='chat_button'
|
|
97
89
|
ref={this.refButton}
|
|
98
|
-
isShow={!
|
|
90
|
+
isShow={!isShowWidget}
|
|
99
91
|
onClick={(e) => this.showWidget(e)}
|
|
92
|
+
onSelectQuickReply={(msg) => this.onSelectQuickReply(msg)}
|
|
100
93
|
t={this.props.t}
|
|
101
94
|
/>
|
|
102
95
|
<Widget
|
|
103
96
|
plugin={this.props.plugin}
|
|
104
97
|
store={this.props.store}
|
|
105
|
-
view={
|
|
106
|
-
cid={
|
|
107
|
-
isShow={
|
|
98
|
+
view={widgetView}
|
|
99
|
+
cid={widgetConvoId}
|
|
100
|
+
isShow={isShowWidget}
|
|
108
101
|
onClose={(a) => this.onWidgetClose(a)}
|
|
109
102
|
onGo={(a) => this.showWidget(a)}
|
|
110
103
|
t={this.props.t}
|
|
@@ -124,7 +117,8 @@ export default class Main extends Com {
|
|
|
124
117
|
if (!$widget) return
|
|
125
118
|
if ($widget.wasFormInputed) return
|
|
126
119
|
if (ev.type !== 'message_sent') return
|
|
127
|
-
|
|
120
|
+
let isShowWidget = sb.get(this.props.store.matchLastview(), 'screen') === 'widget'
|
|
121
|
+
if (!isShowWidget) return
|
|
128
122
|
|
|
129
123
|
let byType = sb.get(ev, 'by.type')
|
|
130
124
|
let byid = sb.get(ev, 'by.id') || ''
|
|
@@ -140,50 +134,39 @@ export default class Main extends Com {
|
|
|
140
134
|
if (this.props.store.isMobile()) return
|
|
141
135
|
|
|
142
136
|
if (this.props.plugin._no_auto_expand) return
|
|
143
|
-
|
|
144
|
-
if (this.props.store.matchHasManuallyClosed()) return
|
|
137
|
+
return
|
|
145
138
|
|
|
146
139
|
let convoM = this.props.store.matchConvo('*')
|
|
147
140
|
let redconvo = sb.find(convoM, (convo) => !sb.isConvoSeen(convo, this.props.store.matchUser().id))
|
|
148
141
|
if (!redconvo || !redconvo.id) return
|
|
149
|
-
|
|
142
|
+
let isShowWidget = sb.get(this.props.store.matchLastview(), 'screen') === 'widget'
|
|
143
|
+
if (!isShowWidget) this.showWidget({view: 'chat', cid: redconvo.id})
|
|
150
144
|
}
|
|
151
145
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
146
|
+
onSelectQuickReply(message) {
|
|
147
|
+
this.showWidget({view: 'chat', cid: message.conversation_id})
|
|
148
|
+
this.forceUpdate(() => {
|
|
149
|
+
this.refWidget.current && this.refWidget.current.sendMessage(message)
|
|
150
|
+
})
|
|
158
151
|
}
|
|
159
152
|
|
|
160
153
|
async showWidget(p) {
|
|
161
|
-
this.refButton.current && this.refButton.current.ClearPreview()
|
|
162
|
-
if (!p.view) {
|
|
163
|
-
let lastview = this.props.store.matchLastview() || {}
|
|
164
|
-
p.view = sb.get(lastview, 'view')
|
|
165
|
-
p.cid = sb.get(lastview, 'opts.cid')
|
|
166
|
-
}
|
|
167
|
-
p = p || {}
|
|
154
|
+
//this.refButton.current && this.refButton.current.ClearPreview()
|
|
168
155
|
|
|
156
|
+
let cid = p.cid
|
|
157
|
+
let newView = {screen: 'widget', minimized: 0, view: p.view}
|
|
169
158
|
if (!p.view && !p.cid) {
|
|
170
159
|
let convoM = this.props.store.matchConvo('*')
|
|
171
160
|
let redconvo = sb.find(convoM, (convo) => !sb.isConvoSeen(convo, this.props.store.matchUser().id))
|
|
172
161
|
// try to show first convo
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
cid = sb.get(redconvo, 'id', sb.get(convoM, '0.id'))
|
|
163
|
+
newView.view = 'chat'
|
|
175
164
|
}
|
|
165
|
+
if (cid) newView.opts = {cid}
|
|
176
166
|
|
|
177
167
|
if (this.props.store.isMobile()) modifyViewport()
|
|
178
|
-
this.
|
|
179
|
-
this.props.store.setIsOpen(true)
|
|
180
|
-
|
|
181
|
-
// lazy load widget
|
|
182
|
-
// if (!Widget) Widget = (await loadWidget()).default
|
|
183
|
-
|
|
168
|
+
this.props.store.updateLastview(newView)
|
|
184
169
|
this.forceUpdate()
|
|
185
|
-
this.setState({isShowWidget: true})
|
|
186
|
-
this.props.store.setLastview(p.view, {cid: p.cid})
|
|
187
170
|
}
|
|
188
171
|
|
|
189
172
|
applyMessage(text) {
|
|
@@ -204,17 +187,12 @@ export default class Main extends Com {
|
|
|
204
187
|
|
|
205
188
|
hideWidget() {
|
|
206
189
|
restoreViewport()
|
|
207
|
-
this.props.store.
|
|
208
|
-
this.
|
|
190
|
+
this.props.store.updateLastview({screen: 'button', previewEvent: {}})
|
|
191
|
+
this.forceUpdate()
|
|
209
192
|
}
|
|
210
193
|
|
|
211
194
|
onWidgetClose() {
|
|
212
|
-
this.refButton.current && this.refButton.current.ClearPreview()
|
|
213
|
-
// need call closePreview if not this will display default agent avatar and account name
|
|
214
|
-
this.refButton.current && this.refButton.current.ClosePreview()
|
|
215
|
-
this.props.store.setHasManuallyClosed()
|
|
216
195
|
this.hideWidget()
|
|
217
|
-
|
|
218
196
|
// emit event close widget
|
|
219
197
|
this.props.store.emitCloseWidgetEvent()
|
|
220
198
|
}
|
package/src/store/store.js
CHANGED
|
@@ -466,13 +466,21 @@ export default class Store {
|
|
|
466
466
|
|
|
467
467
|
// make sure last view of correct user
|
|
468
468
|
let user = this.cache.match('user') || {}
|
|
469
|
-
if (!user.id) return {}
|
|
470
|
-
if (lastView.user_id != user.id) return {}
|
|
469
|
+
if (!user.id) return { screen: 'preview' }
|
|
470
|
+
if (lastView.user_id != user.id) return { screen: 'preview' }
|
|
471
|
+
|
|
472
|
+
if (!lastView.screen) {
|
|
473
|
+
lastView.screen = 'preview' // mode preview allow load default greeting
|
|
474
|
+
|
|
475
|
+
// backward compatible for user currently view chat
|
|
476
|
+
if (lastView.view === 'list' || lastView.view === 'chat') {
|
|
477
|
+
lastView.screen = 'widget'
|
|
478
|
+
}
|
|
479
|
+
}
|
|
471
480
|
return lastView
|
|
472
481
|
}
|
|
473
482
|
|
|
474
483
|
matchIsOpen = () => !!this.kv.match('isopen') // is widget currently open
|
|
475
|
-
matchHasManuallyClosed = () => !!this.kv.match('hasManuallyClosed') // true if user has ever closed the widget
|
|
476
484
|
matchClosePreviewAt = () => this.kv.match('close_preview_at') || 0
|
|
477
485
|
|
|
478
486
|
checkFormToken = (accid, token) => this.api.checkFormToken(accid, token)
|
|
@@ -1212,19 +1220,18 @@ export default class Store {
|
|
|
1212
1220
|
onResetCSS = (o, cb) => this.pubsub.on2(o, 'resetCSS', cb)
|
|
1213
1221
|
onHighlight = (o, cb) => this.pubsub.on2(o, 'highlight', cb)
|
|
1214
1222
|
|
|
1215
|
-
setHasManuallyClosed = () => this.kv.put('hasManuallyClosed', true)
|
|
1216
|
-
setIsOpen = (isopen) => {
|
|
1217
|
-
let lastisopen = this.kv.match('isopen')
|
|
1218
|
-
this.kv.put('isopen', isopen)
|
|
1219
|
-
if (!lastisopen && isopen) {
|
|
1220
|
-
sendEventToThirdParty('SUBIZ Chat', 'Opened', 'Subiz Windows')
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
1223
|
closePreview = () => this.kv.put('close_preview_at', new sb.Date().getTime())
|
|
1224
|
-
|
|
1224
|
+
updateLastview = (obj) => {
|
|
1225
1225
|
let user = this.cache.match('user') || {}
|
|
1226
1226
|
if (!user.id) return // store not init
|
|
1227
|
-
|
|
1227
|
+
let lastview = this.matchLastview() || {}
|
|
1228
|
+
lastview = {
|
|
1229
|
+
...lastview,
|
|
1230
|
+
...obj,
|
|
1231
|
+
user_id: user.id,
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
this.kv.put('lastview', lastview)
|
|
1228
1235
|
}
|
|
1229
1236
|
|
|
1230
1237
|
matchLastPluginRun(pluginid) {
|