@subiz/widget-v4 4.1.210 → 4.1.211
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/README.md +21 -2
- package/assets/less/chatbox.less +9 -0
- package/assets/less/form.less +10 -0
- package/assets/less/message.less +114 -13
- package/assets/less/widget.less +21 -16
- package/compiled_src/call/css.js +1 -1
- package/compiled_src/chatbox/Buttons.js +7 -4
- package/compiled_src/chatbox/ChatButton.js +115 -29
- package/compiled_src/chatbox/Event.js +37 -5
- package/compiled_src/chatbox/Events.js +348 -129
- package/compiled_src/chatbox/FormAttachment.js +1 -1
- package/compiled_src/chatbox/Header.js +6 -2
- package/compiled_src/chatbox/InfoMessage.js +1 -1
- package/compiled_src/chatbox/MessageInput.js +24 -9
- package/compiled_src/chatbox/OrderAttachments.js +13 -13
- package/compiled_src/chatbox/QuoteMessage.js +3 -2
- package/compiled_src/chatbox/TextMessage.js +22 -18
- package/compiled_src/chatbox/Widget.js +200 -129
- package/compiled_src/chatbox/block.js +39 -29
- package/compiled_src/chatbox/conversation-history.js +44 -0
- package/compiled_src/chatbox/event-layout.js +59 -0
- package/compiled_src/chatbox/greeting.js +32 -0
- package/compiled_src/common.js +13 -9
- package/compiled_src/form/css.js +1 -1
- package/compiled_src/lib.js +22 -32
- package/compiled_src/notif/css.js +1 -1
- package/compiled_src/plugin.js +11 -18
- package/compiled_src/popup/css.js +1 -1
- package/compiled_src/popup/popup.js +1 -1
- package/compiled_src/store/api.js +0 -2
- package/compiled_src/store/api_fake.js +1 -1
- package/compiled_src/store/attachments.js +28 -0
- package/compiled_src/store/chain.js +24 -10
- package/compiled_src/store/kv.js +9 -13
- package/compiled_src/store/lsdb.js +1 -1
- package/compiled_src/store/store.js +356 -117
- package/compiled_src/util/common.js +48 -41
- package/compiled_src/util/event.js +15 -0
- package/compiled_src/util/pubsub.js +28 -13
- package/compiled_src/util/url.js +18 -0
- package/dist/.HASH +1 -0
- package/dist/127.js +13 -13
- package/dist/132.js +1 -1
- package/dist/1a0ddc53cbb.127.js +1 -0
- package/dist/{1a0d80f6e72.132.js → 1a0ddc53cbb.132.js} +1 -1
- package/dist/1a0ddc53cbb.278.js +1 -0
- package/dist/{1a0d80f6e72.339.js → 1a0ddc53cbb.339.js} +1 -1
- package/dist/1a0ddc53cbb.app.js +1 -0
- package/dist/{1a0d80f6e72.chat.html → 1a0ddc53cbb.chat.html} +1 -1
- package/dist/1a0ddc53cbb.chat.js +1 -0
- package/dist/{1a0d80f6e72.form.html → 1a0ddc53cbb.form.html} +1 -1
- package/dist/1a0ddc53cbb.form.js +1 -0
- package/dist/{1a0d80f6e72.index.html → 1a0ddc53cbb.index.html} +1 -1
- package/dist/{1a0d80f6e72.library.html → 1a0ddc53cbb.library.html} +1 -1
- package/dist/1a0ddc53cbb.library.js +1 -0
- package/dist/{1a0d80f6e72.preview.html → 1a0ddc53cbb.preview.html} +1 -1
- package/dist/1a0ddc53cbb.preview.js +1 -0
- package/dist/1a0ddc53cbb.webview.js +1 -0
- package/dist/screenshoot.js +1492 -616
- package/package.json +10 -3
- package/src/chatbox/Buttons.js +5 -4
- package/src/chatbox/ChatButton.js +120 -39
- package/src/chatbox/Event.js +38 -5
- package/src/chatbox/Events.js +306 -134
- package/src/chatbox/FormAttachment.js +1 -1
- package/src/chatbox/Header.js +4 -4
- package/src/chatbox/InfoMessage.js +1 -1
- package/src/chatbox/MessageInput.js +15 -10
- package/src/chatbox/OrderAttachments.js +13 -13
- package/src/chatbox/QuoteMessage.js +3 -2
- package/src/chatbox/TextMessage.js +21 -20
- package/src/chatbox/Widget.js +150 -150
- package/src/chatbox/block.js +29 -27
- package/src/chatbox/conversation-history.js +37 -0
- package/src/chatbox/event-layout.js +72 -0
- package/src/chatbox/greeting.js +13 -0
- package/src/common.js +15 -9
- package/src/lib.js +22 -35
- package/src/plugin.js +11 -13
- package/src/popup/popup.js +1 -1
- package/src/store/api.js +0 -2
- package/src/store/api_fake.js +1 -1
- package/src/store/attachments.js +21 -0
- package/src/store/chain.js +25 -12
- package/src/store/kv.js +10 -19
- package/src/store/lsdb.js +1 -1
- package/src/store/store.js +313 -130
- package/src/util/common.js +48 -43
- package/src/util/event.js +7 -0
- package/src/util/pubsub.js +27 -8
- package/src/util/url.js +14 -0
- package/test.cjs +59 -0
- package/assets/less/contact.less +0 -126
- package/compiled_src/util/common.test.js +0 -414
- package/compiled_src/util/event.test.js +0 -38
- package/compiled_src/util/extractor.test.js +0 -299
- package/compiled_src/util/extractor.test2.js +0 -61
- package/compiled_src/util/gate.test.js +0 -18
- package/compiled_src/util/pubsub.test.js +0 -35
- package/dist/1a0d80f6e72.127.js +0 -1
- package/dist/1a0d80f6e72.278.js +0 -1
- package/dist/1a0d80f6e72.74.js +0 -1
- package/dist/1a0d80f6e72.997.js +0 -1
- package/dist/1a0d80f6e72.app.js +0 -1
- package/dist/1a0d80f6e72.chat.js +0 -1
- package/dist/1a0d80f6e72.form.js +0 -1
- package/dist/1a0d80f6e72.library.js +0 -1
- package/dist/1a0d80f6e72.preview.js +0 -1
- package/dist/1a0d80f6e72.webview.js +0 -1
- package/dist/74.js +0 -376
- package/dist/997.js +0 -37
- package/dist/HASH +0 -1
- package/src/contact/contact.js +0 -400
- package/src/contact/css.js +0 -1
- package/src/util/common.test.js +0 -301
- package/src/util/event.test.js +0 -31
- package/src/util/extractor.test.js +0 -240
- package/src/util/extractor.test2.js +0 -56
- package/src/util/gate.test.js +0 -20
- package/src/util/pubsub.test.js +0 -37
- /package/dist/{1a0d80f6e72.185.js → 1a0ddc53cbb.185.js} +0 -0
- /package/dist/{1a0d80f6e72.27.js → 1a0ddc53cbb.27.js} +0 -0
- /package/dist/{1a0d80f6e72.459.js → 1a0ddc53cbb.459.js} +0 -0
- /package/dist/{1a0d80f6e72.490.js → 1a0ddc53cbb.490.js} +0 -0
|
@@ -11,6 +11,7 @@ var _AgentsAvatar = _interopRequireDefault(require("./AgentsAvatar.js"));
|
|
|
11
11
|
var _Header = _interopRequireDefault(require("./Header.js"));
|
|
12
12
|
var _MessageInput = _interopRequireDefault(require("./MessageInput.js"));
|
|
13
13
|
var _Events = _interopRequireDefault(require("./Events.js"));
|
|
14
|
+
var _greeting = require("./greeting.js");
|
|
14
15
|
var _Rating = _interopRequireDefault(require("./Rating.js"));
|
|
15
16
|
var _ConnectionStatus = _interopRequireDefault(require("./ConnectionStatus.js"));
|
|
16
17
|
var _ListField = _interopRequireDefault(require("./ListField.js"));
|
|
@@ -32,51 +33,12 @@ class Widget extends _common.Com {
|
|
|
32
33
|
constructor(props) {
|
|
33
34
|
super(props);
|
|
34
35
|
_defineProperty(this, "msgInput", (0, _preact.createRef)());
|
|
35
|
-
_defineProperty(this, "findMissingRTMessage", async started => {
|
|
36
|
-
let messageSentDict = this.props.store.listAgentRealtimeMessageSent();
|
|
37
|
-
let res1 = await this.props.store.sbzListConversations();
|
|
38
|
-
let conversions = _index.default.get(res1, 'body.conversations') || [];
|
|
39
|
-
let cids = _index.default.map(conversions, convo => convo.id);
|
|
40
|
-
let promises = _index.default.map(cids, cid => this.props.store.sbzListMessages(cid));
|
|
41
|
-
let msgReses = await Promise.all(promises);
|
|
42
|
-
_index.default.map(msgReses, msgRes => {
|
|
43
|
-
let messages = _index.default.get(msgRes, 'body') || [];
|
|
44
|
-
_index.default.map(messages, ev => {
|
|
45
|
-
if (ev.created < started) return;
|
|
46
|
-
if (ev.type !== 'message_sent') return;
|
|
47
|
-
if (_index.default.get(ev, 'by.type') === 'user') return;
|
|
48
|
-
console.log('check ev pass condition', ev);
|
|
49
|
-
if (!messageSentDict[ev.id] && !this.debugAgentSentEvIds[ev.id]) {
|
|
50
|
-
let accid = _index.default.get(this.props.store.matchAccount(), 'id');
|
|
51
|
-
this.props.store.sendBugReport(`[WIDGET ${accid}] Missing agent message sent evid ${ev.id}, cid ${_index.default.convoOfEv(ev)}, ev_created ${ev.created}, FE timestamp ${Date.now()}, Init Debug timestamp ${started}`);
|
|
52
|
-
this.debugAgentSentEvIds[ev.id] = true;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
_defineProperty(this, "debugRTAgentMessageSent", async () => {
|
|
58
|
-
try {
|
|
59
|
-
let debugAccountIds = this.props.store.matchDebugAccountIds();
|
|
60
|
-
let accid = _index.default.get(this.props.store.matchAccount(), 'id');
|
|
61
|
-
if (!debugAccountIds.includes(accid)) return;
|
|
62
|
-
console.log('START check RT agent message with BE source');
|
|
63
|
-
let started = Date.now();
|
|
64
|
-
this.findMissingRTMessage(started);
|
|
65
|
-
for (let i = 0; i < 100_000; i++) {
|
|
66
|
-
await _index.default.sleep(120_000);
|
|
67
|
-
console.log('LOOP check RT agent message with BE source', i);
|
|
68
|
-
this.findMissingRTMessage(started);
|
|
69
|
-
}
|
|
70
|
-
} catch (err) {
|
|
71
|
-
this.props.store.sendBugReport(`debugRTAgentMessageSent ERROR ${err.stack}`);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
36
|
_defineProperty(this, "formMounted", form => {
|
|
75
37
|
let formData = this.fillForm(form);
|
|
76
38
|
if (form.question_required || this.state.quickReplyMessage.text) {
|
|
77
39
|
formData['question'] = {
|
|
78
40
|
key: 'question',
|
|
79
|
-
is_required:
|
|
41
|
+
is_required: false,
|
|
80
42
|
label: this.props.t.i18n(_index.default.get(form, `i18n_question_label`, {})) || form.question_label,
|
|
81
43
|
type: 'text',
|
|
82
44
|
value: this.state.quickReplyMessage.text
|
|
@@ -87,14 +49,118 @@ class Widget extends _common.Com {
|
|
|
87
49
|
});
|
|
88
50
|
if (!this.props.store.isMobile() && !form._updated) this.focusInput();
|
|
89
51
|
});
|
|
90
|
-
_defineProperty(this, "sendMessage", async message
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
52
|
+
_defineProperty(this, "sendMessage", async (message, {
|
|
53
|
+
formSubmitted = false,
|
|
54
|
+
groupId
|
|
55
|
+
} = {}) => {
|
|
56
|
+
if (this._sendingNewConversation) return false;
|
|
57
|
+
if (_index.default.get(this.props.store.matchConvo(this.props.cid), 'state') === 'ended') {
|
|
58
|
+
const form = this.startingConversationForm();
|
|
59
|
+
if (form && (_index.default.size(form.groups) || form.group_required || this.isFormRequired(''))) {
|
|
60
|
+
this.setState({
|
|
61
|
+
restartForm: true,
|
|
62
|
+
quickReplyMessage: message
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this._sendingNewConversation = true;
|
|
67
|
+
this.setState({
|
|
68
|
+
creating: true,
|
|
69
|
+
creatingError: null
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
const {
|
|
73
|
+
convo,
|
|
74
|
+
error
|
|
75
|
+
} = await this.props.store.startConvo({
|
|
76
|
+
locale: this.props.t.locale(),
|
|
77
|
+
message: message.text,
|
|
78
|
+
initial_by: this.props.store.matchUser().id
|
|
79
|
+
});
|
|
80
|
+
if (error) {
|
|
81
|
+
this.setState({
|
|
82
|
+
creatingError: error
|
|
83
|
+
});
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
await this.props.store.sendConvoEvent(convo.id, 'message_sent', {
|
|
87
|
+
message
|
|
88
|
+
});
|
|
89
|
+
this.props.onGo({
|
|
90
|
+
view: 'chat',
|
|
91
|
+
cid: convo.id
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
this._sendingNewConversation = false;
|
|
95
|
+
this.setState({
|
|
96
|
+
creating: false
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const form = this.startingConversationForm();
|
|
102
|
+
const needsGroup = form && !this.hasSentMessage(this.props.cid) && (_index.default.size(form.groups) || form.group_required);
|
|
103
|
+
if (!formSubmitted && (this.isFormRequired() || needsGroup)) {
|
|
104
|
+
this.setState({
|
|
105
|
+
clickedJoin: true,
|
|
106
|
+
quickReplyMessage: message
|
|
107
|
+
});
|
|
95
108
|
return;
|
|
96
109
|
}
|
|
97
110
|
let text = message.text;
|
|
111
|
+
const localConvo = this.props.store.matchConvo(this.props.cid);
|
|
112
|
+
if (localConvo && localConvo.light_type === 'widget') {
|
|
113
|
+
this._sendingNewConversation = true;
|
|
114
|
+
this.setState({
|
|
115
|
+
creating: true,
|
|
116
|
+
creatingError: null
|
|
117
|
+
});
|
|
118
|
+
try {
|
|
119
|
+
const {
|
|
120
|
+
convo,
|
|
121
|
+
error
|
|
122
|
+
} = await this.props.store.startConvo({
|
|
123
|
+
locale: localConvo.locale,
|
|
124
|
+
message: text,
|
|
125
|
+
group_id: groupId,
|
|
126
|
+
initial_by: this.props.store.matchUser().id,
|
|
127
|
+
greeting_message: localConvo.events[0]
|
|
128
|
+
});
|
|
129
|
+
if (error || !convo) {
|
|
130
|
+
this.setState({
|
|
131
|
+
creatingError: error || 'start_failed'
|
|
132
|
+
});
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
this.props.store.promoteWidgetConvo(localConvo.id, convo.id);
|
|
136
|
+
const sending = this.props.store.sendConvoEvent(convo.id, 'message_sent', {
|
|
137
|
+
message
|
|
138
|
+
});
|
|
139
|
+
this.props.onGo({
|
|
140
|
+
view: 'chat',
|
|
141
|
+
cid: convo.id
|
|
142
|
+
});
|
|
143
|
+
await sending;
|
|
144
|
+
this.userSent[convo.id] = true;
|
|
145
|
+
if (formSubmitted && form && form.end_conversation_after_submit) await this.props.store.endConvo(convo.id);
|
|
146
|
+
this.setState({
|
|
147
|
+
clickedJoin: false,
|
|
148
|
+
restartForm: false,
|
|
149
|
+
quickReplyMessage: {}
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
this.setState({
|
|
153
|
+
creatingError: error
|
|
154
|
+
});
|
|
155
|
+
return false;
|
|
156
|
+
} finally {
|
|
157
|
+
this._sendingNewConversation = false;
|
|
158
|
+
this.setState({
|
|
159
|
+
creating: false
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
98
164
|
if (this.props.cid && this.props.cid.startsWith('cslight')) {
|
|
99
165
|
let cid = this.props.cid;
|
|
100
166
|
this._creating = (this._creating || 0) + 1;
|
|
@@ -165,14 +231,15 @@ class Widget extends _common.Com {
|
|
|
165
231
|
});
|
|
166
232
|
return;
|
|
167
233
|
}
|
|
168
|
-
|
|
234
|
+
const sending = this.props.store.sendConvoEvent(convo.id, 'message_sent', {
|
|
169
235
|
message
|
|
170
236
|
});
|
|
171
|
-
if (_creating != this._creating) return;
|
|
172
237
|
this.props.onGo({
|
|
173
238
|
view: 'chat',
|
|
174
239
|
cid: convo.id
|
|
175
240
|
});
|
|
241
|
+
await sending;
|
|
242
|
+
if (_creating != this._creating) return;
|
|
176
243
|
this.setState({
|
|
177
244
|
creating: false
|
|
178
245
|
});
|
|
@@ -212,7 +279,6 @@ class Widget extends _common.Com {
|
|
|
212
279
|
this.focusInput();
|
|
213
280
|
});
|
|
214
281
|
this.userSent = {};
|
|
215
|
-
this.debugAgentSentEvIds = {};
|
|
216
282
|
this.wasFormInputed = false;
|
|
217
283
|
this.setState({
|
|
218
284
|
creating: false,
|
|
@@ -228,7 +294,6 @@ class Widget extends _common.Com {
|
|
|
228
294
|
componentDidMount() {
|
|
229
295
|
if (!this.props.store.isMobile()) this.focusInput();
|
|
230
296
|
this.updateFormDataFields();
|
|
231
|
-
this.debugRTAgentMessageSent();
|
|
232
297
|
}
|
|
233
298
|
applyMessage(text) {
|
|
234
299
|
this.focusInput(text);
|
|
@@ -243,6 +308,7 @@ class Widget extends _common.Com {
|
|
|
243
308
|
this.closeOrder();
|
|
244
309
|
this.setState({
|
|
245
310
|
clickedJoin: false,
|
|
311
|
+
restartForm: false,
|
|
246
312
|
quickReplyMessage: {}
|
|
247
313
|
});
|
|
248
314
|
_index.default.setTimeout(() => {
|
|
@@ -252,19 +318,14 @@ class Widget extends _common.Com {
|
|
|
252
318
|
this.updateFormDataFields();
|
|
253
319
|
}
|
|
254
320
|
}
|
|
321
|
+
componentWillUnmount() {
|
|
322
|
+
this.cancelContainerFocus();
|
|
323
|
+
}
|
|
255
324
|
ShowTyping() {
|
|
256
325
|
this.$events && this.$events.ShowTyping();
|
|
257
326
|
}
|
|
258
327
|
shouldShowForm() {
|
|
259
|
-
|
|
260
|
-
let accountSetting = this.props.plugin.chatbox || {};
|
|
261
|
-
let acc = this.props.store.matchAccount() || {};
|
|
262
|
-
if (_index.default.get(accountSetting, 'prechat_form.enabled')) form = accountSetting.prechat_form;
|
|
263
|
-
let offlineEnabled = _index.default.get(accountSetting, 'offline_form.enabled');
|
|
264
|
-
if (this.isOffline(acc, accountSetting) && offlineEnabled) form = accountSetting.offline_form;
|
|
265
|
-
if (!this.hasSentMessage(this.props.cid) && form && (_index.default.size(form.groups) || form.group_required)) return true;
|
|
266
|
-
let formRequired = this.isFormRequired();
|
|
267
|
-
return formRequired && !this.props.cid || formRequired && this.props.cid && this.state.clickedJoin;
|
|
328
|
+
return !!(this.state.restartForm || this.state.clickedJoin);
|
|
268
329
|
}
|
|
269
330
|
render() {
|
|
270
331
|
let showform = this.shouldShowForm();
|
|
@@ -328,42 +389,22 @@ class Widget extends _common.Com {
|
|
|
328
389
|
_index.default.map(formData, (field, key) => {
|
|
329
390
|
field = Object.assign({}, field);
|
|
330
391
|
field.is_empty_error = false;
|
|
331
|
-
if (field.is_required && (field.value
|
|
392
|
+
if (field.is_required && (field.value == null || typeof field.value === 'string' && !field.value.trim() || _index.default.size(field.value) === 0 && Array.isArray(field.value))) {
|
|
332
393
|
field.is_empty_error = true;
|
|
333
394
|
field.error = this.props.t('error_empty');
|
|
334
395
|
} else field.error = '';
|
|
335
|
-
if (key
|
|
336
|
-
|
|
337
|
-
if (!_index.default.isEmail(field.value)) {
|
|
338
|
-
field.error = this.props.t('error_email_invalid');
|
|
339
|
-
}
|
|
340
|
-
} else {
|
|
341
|
-
let value = field.value || '';
|
|
342
|
-
if (typeof value !== 'string') value = value + '';
|
|
343
|
-
if (value.trim() && !_index.default.isEmail(field.value)) {
|
|
344
|
-
field.error = this.props.t('error_email_invalid');
|
|
345
|
-
}
|
|
346
|
-
}
|
|
396
|
+
if (key === 'attr:emails' && !field.error && String(field.value ?? '').trim() && !_index.default.isEmail(field.value)) {
|
|
397
|
+
field.error = this.props.t('error_email_invalid');
|
|
347
398
|
}
|
|
348
|
-
if (key
|
|
349
|
-
|
|
350
|
-
if (!_index.default.isPhone(field.value)) {
|
|
351
|
-
field.error = this.props.t('error_phone_invalid');
|
|
352
|
-
}
|
|
353
|
-
} else {
|
|
354
|
-
let value = field.value || '';
|
|
355
|
-
if (typeof value !== 'string') value = value + '';
|
|
356
|
-
if (value.trim() && !_index.default.isPhone(field.value)) {
|
|
357
|
-
field.error = this.props.t('error_phone_invalid');
|
|
358
|
-
}
|
|
359
|
-
}
|
|
399
|
+
if (key === 'attr:phones' && !field.error && String(field.value ?? '').trim() && !_index.default.isPhone(field.value)) {
|
|
400
|
+
field.error = this.props.t('error_phone_invalid');
|
|
360
401
|
}
|
|
361
402
|
newformdata[key] = field;
|
|
362
403
|
});
|
|
363
404
|
return newformdata;
|
|
364
405
|
}
|
|
365
406
|
async submitPrechatForm(form, formName) {
|
|
366
|
-
if (this.state.submiting) return;
|
|
407
|
+
if (this.state.submiting || this.state.creating) return;
|
|
367
408
|
let newData = this.validateForm(this.state.formData);
|
|
368
409
|
let hasError = _index.default.find(newData, field => !!field.error);
|
|
369
410
|
if (hasError) {
|
|
@@ -378,6 +419,8 @@ class Widget extends _common.Com {
|
|
|
378
419
|
let is_lead = false;
|
|
379
420
|
_index.default.map(data, (field, key) => {
|
|
380
421
|
if (!key.startsWith('attr:')) return;
|
|
422
|
+
if (key === 'attr:phones') field.value = String(field.value ?? '').trim().replace(/[(). \-]/g, '');
|
|
423
|
+
if (key === 'attr:emails') field.value = String(field.value ?? '').trim();
|
|
381
424
|
var attr = {
|
|
382
425
|
key: key.substr(5)
|
|
383
426
|
};
|
|
@@ -392,7 +435,8 @@ class Widget extends _common.Com {
|
|
|
392
435
|
key: 'lead_source',
|
|
393
436
|
text: 'widget'
|
|
394
437
|
});
|
|
395
|
-
|
|
438
|
+
const question = String(_index.default.get(data, 'question.value', '') ?? '').trim();
|
|
439
|
+
const firstmsg = question || (/^vi(?:[-_]|$)/i.test(navigator.language || '') ? 'Xin chào' : 'Hello');
|
|
396
440
|
let groupid = _index.default.get(data, 'group.value', '');
|
|
397
441
|
this._creating = (this._creating || 0) + 1;
|
|
398
442
|
let _creating = this._creating;
|
|
@@ -410,7 +454,7 @@ class Widget extends _common.Com {
|
|
|
410
454
|
await _index.default.sleep(500);
|
|
411
455
|
if (_creating != this._creating) return;
|
|
412
456
|
if (this.props.cid && this.props.cid.startsWith('cslight')) {
|
|
413
|
-
this.sendMessage({
|
|
457
|
+
await this.sendMessage({
|
|
414
458
|
text: firstmsg,
|
|
415
459
|
format: 'plaintext',
|
|
416
460
|
fields: [{
|
|
@@ -418,10 +462,13 @@ class Widget extends _common.Com {
|
|
|
418
462
|
value: _index.default.stringify(groupid)
|
|
419
463
|
}],
|
|
420
464
|
attachments: this.state.quickReplyMessage.attachments
|
|
465
|
+
}, {
|
|
466
|
+
formSubmitted: true,
|
|
467
|
+
groupId: groupid
|
|
421
468
|
});
|
|
422
469
|
return;
|
|
423
470
|
}
|
|
424
|
-
if (this.props.cid) {
|
|
471
|
+
if (this.props.cid && _index.default.get(this.props.store.matchConvo(this.props.cid), 'state') !== 'ended') {
|
|
425
472
|
this.setState({
|
|
426
473
|
clickedJoin: false
|
|
427
474
|
});
|
|
@@ -447,7 +494,8 @@ class Widget extends _common.Com {
|
|
|
447
494
|
}
|
|
448
495
|
let message = {
|
|
449
496
|
text: firstmsg,
|
|
450
|
-
format: 'plaintext'
|
|
497
|
+
format: 'plaintext',
|
|
498
|
+
attachments: this.state.quickReplyMessage.attachments
|
|
451
499
|
};
|
|
452
500
|
let req = {
|
|
453
501
|
group_id: groupid,
|
|
@@ -476,9 +524,12 @@ class Widget extends _common.Com {
|
|
|
476
524
|
message
|
|
477
525
|
});
|
|
478
526
|
if (_creating != this._creating) return;
|
|
527
|
+
if (form.end_conversation_after_submit) await this.props.store.endConvo(newconvoid);
|
|
528
|
+
if (_creating != this._creating) return;
|
|
479
529
|
this.setState({
|
|
480
530
|
creating: false,
|
|
481
531
|
clickedJoin: false,
|
|
532
|
+
restartForm: false,
|
|
482
533
|
quickReplyMessage: {}
|
|
483
534
|
});
|
|
484
535
|
this.props.onGo({
|
|
@@ -509,6 +560,7 @@ class Widget extends _common.Com {
|
|
|
509
560
|
if (!field) return;
|
|
510
561
|
field.value = val;
|
|
511
562
|
field.error = undefined;
|
|
563
|
+
field.is_empty_error = false;
|
|
512
564
|
this.setState({
|
|
513
565
|
formData
|
|
514
566
|
});
|
|
@@ -629,7 +681,7 @@ class Widget extends _common.Com {
|
|
|
629
681
|
renderFields(form, formName) {
|
|
630
682
|
if (_index.default.size(this.state.formData) === 0) return null;
|
|
631
683
|
let $fields = _index.default.map(this.state.formData, (field, key) => {
|
|
632
|
-
if (this.state.quickReplyMessage.
|
|
684
|
+
if (key === 'question' && _index.default.find(this.state.quickReplyMessage.attachments, att => att.type === 'postback')) return null;
|
|
633
685
|
let $field = null;
|
|
634
686
|
var errclass = field.error ? 'input--error' : '';
|
|
635
687
|
if (field.type === 'text') {
|
|
@@ -662,7 +714,11 @@ class Widget extends _common.Com {
|
|
|
662
714
|
this['form_' + encode(key)] = ref;
|
|
663
715
|
},
|
|
664
716
|
class: `form-control ${errclass}`,
|
|
665
|
-
type:
|
|
717
|
+
type: key === 'attr:phones' ? 'tel' : key === 'attr:emails' ? 'email' : 'text',
|
|
718
|
+
inputMode: key === 'attr:phones' ? 'tel' : key === 'attr:emails' ? 'email' : undefined,
|
|
719
|
+
autoComplete: key === 'attr:phones' ? 'tel' : key === 'attr:emails' ? 'email' : undefined,
|
|
720
|
+
"aria-invalid": field.error ? 'true' : undefined,
|
|
721
|
+
"aria-describedby": field.error ? 'form-error_' + encode(key) : undefined
|
|
666
722
|
});
|
|
667
723
|
}
|
|
668
724
|
} else if (field.type === 'number') {
|
|
@@ -746,6 +802,8 @@ class Widget extends _common.Com {
|
|
|
746
802
|
}, label, field.is_required ? (0, _preact.h)("span", {
|
|
747
803
|
class: "red"
|
|
748
804
|
}, "*") : ''), $field, field.error ? (0, _preact.h)("div", {
|
|
805
|
+
id: 'form-error_' + encode(key),
|
|
806
|
+
role: "alert",
|
|
749
807
|
class: "form-control--valid-input--error"
|
|
750
808
|
}, field.error) : '');
|
|
751
809
|
});
|
|
@@ -758,9 +816,10 @@ class Widget extends _common.Com {
|
|
|
758
816
|
if (!title) title = _index.default.get(form, 'title', this.props.t('capture_lead_title'));
|
|
759
817
|
title = title.replace('↵', '');
|
|
760
818
|
let btncls = 'btn--start-convo ';
|
|
761
|
-
let hasError = _index.default.find(this.state.formData, field => !!field.error);
|
|
762
819
|
let newData = this.validateForm(this.state.formData);
|
|
763
820
|
let hasEmptyError = _index.default.find(newData, field => !!field.is_empty_error);
|
|
821
|
+
const phone = String(_index.default.get(this.state.formData, 'attr:phones.value', '') ?? '').trim();
|
|
822
|
+
const phoneTooShort = phone.length > 0 && phone.length < 5;
|
|
764
823
|
let bodycls = 'widget-body';
|
|
765
824
|
if (this.props.store.isEmbededChatMode()) bodycls += ' embed-chat';
|
|
766
825
|
return (0, _preact.h)("div", {
|
|
@@ -780,12 +839,28 @@ class Widget extends _common.Com {
|
|
|
780
839
|
}), (0, _preact.h)("button", {
|
|
781
840
|
class: btncls,
|
|
782
841
|
onClick: _ => this.submitPrechatForm(form, formName),
|
|
783
|
-
disabled: !!hasEmptyError ||
|
|
842
|
+
disabled: !!hasEmptyError || phoneTooShort || this.state.creating
|
|
784
843
|
}, submitLabel)));
|
|
785
844
|
}
|
|
786
845
|
goToConvo(cid) {
|
|
846
|
+
let view = 'chat';
|
|
847
|
+
if (!cid) {
|
|
848
|
+
const greeting = (0, _greeting.widgetGreeting)(this.props.plugin.chatbox, this.props.t);
|
|
849
|
+
cid = this.props.store.startWidgetConvo(greeting, this.props.t.locale()).convo.id;
|
|
850
|
+
const form = this.startingConversationForm();
|
|
851
|
+
const setting = this.props.plugin.chatbox || {};
|
|
852
|
+
const offline = _index.default.get(setting, 'offline_form.enabled') && this.isOffline(this.props.store.matchAccount() || {}, setting);
|
|
853
|
+
if (form && (offline || this.isFormRequired(cid) || _index.default.size(form.groups) || form.group_required)) {
|
|
854
|
+
view = offline ? 'offline_form' : 'prechat_form';
|
|
855
|
+
this.setState({
|
|
856
|
+
clickedJoin: false,
|
|
857
|
+
restartForm: false,
|
|
858
|
+
quickReplyMessage: {}
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
}
|
|
787
862
|
this.props.onGo({
|
|
788
|
-
view
|
|
863
|
+
view,
|
|
789
864
|
cid
|
|
790
865
|
});
|
|
791
866
|
}
|
|
@@ -859,7 +934,7 @@ class Widget extends _common.Com {
|
|
|
859
934
|
_index.default.setTimeout(() => $input && $input.blur());
|
|
860
935
|
_index.default.setTimeout(() => $input && $input.blur(), 300);
|
|
861
936
|
}
|
|
862
|
-
focusInput(text) {
|
|
937
|
+
focusInput(text, repeat = true) {
|
|
863
938
|
if (this.props.store.isPreview) return;
|
|
864
939
|
if (this.shouldShowForm()) {
|
|
865
940
|
let focusfieldkey = '';
|
|
@@ -884,6 +959,7 @@ class Widget extends _common.Com {
|
|
|
884
959
|
if (text != undefined && typeof text === 'string') {
|
|
885
960
|
$input.applyMessage(text);
|
|
886
961
|
}
|
|
962
|
+
if (!repeat) return $input.focus();
|
|
887
963
|
_index.default.setTimeout(() => $input.focus());
|
|
888
964
|
_index.default.setTimeout(() => $input.focus(), 300);
|
|
889
965
|
}
|
|
@@ -920,21 +996,13 @@ class Widget extends _common.Com {
|
|
|
920
996
|
onSend: this.sendMessage,
|
|
921
997
|
t: this.props.t
|
|
922
998
|
});
|
|
923
|
-
let convo = this.props.store.matchConvo(this.props.cid) || {};
|
|
924
|
-
if (this.isFormRequired() || convo.state === 'ended') {
|
|
925
|
-
$input = (0, _preact.h)("div", {
|
|
926
|
-
class: "message-input message-input--preform"
|
|
927
|
-
}, (0, _preact.h)("button", {
|
|
928
|
-
class: "btn--start-convo",
|
|
929
|
-
onClick: e => this.onStartConvoClick(e)
|
|
930
|
-
}, this.props.t('offline_preform_btn')));
|
|
931
|
-
}
|
|
932
999
|
let bodycls = 'widget-body';
|
|
933
1000
|
if (this.props.store.isEmbededChatMode()) bodycls += ' embed-chat';
|
|
934
1001
|
return (0, _preact.h)("div", {
|
|
935
1002
|
class: bodycls
|
|
936
1003
|
}, (0, _preact.h)("div", {
|
|
937
1004
|
class: "widget-body--content",
|
|
1005
|
+
onPointerDown: () => this.cancelContainerFocus(),
|
|
938
1006
|
onClick: e => this.onContainerClick(e)
|
|
939
1007
|
}, (0, _preact.h)(_Events.default, {
|
|
940
1008
|
isShow: this.props.isShow,
|
|
@@ -944,7 +1012,7 @@ class Widget extends _common.Com {
|
|
|
944
1012
|
onFormSubmit: e => this.onEventFormSubmit(e),
|
|
945
1013
|
ref: ref => this.$events = ref,
|
|
946
1014
|
cid: this.props.cid,
|
|
947
|
-
creating: this.creating,
|
|
1015
|
+
creating: this.state.creating,
|
|
948
1016
|
onSend: e => this.sendMessage(e),
|
|
949
1017
|
onPostback: e => this.createPostback(e),
|
|
950
1018
|
t: this.props.t,
|
|
@@ -971,42 +1039,45 @@ class Widget extends _common.Com {
|
|
|
971
1039
|
t: this.props.t
|
|
972
1040
|
}), $input);
|
|
973
1041
|
}
|
|
974
|
-
async onStartConvoClick() {
|
|
975
|
-
var convo = this.props.store.matchConvo(this.props.cid) || {};
|
|
976
|
-
if (convo.state === 'ended') return this.props.onGo({
|
|
977
|
-
view: 'chat',
|
|
978
|
-
cid: ''
|
|
979
|
-
});
|
|
980
|
-
this.setState({
|
|
981
|
-
clickedJoin: true,
|
|
982
|
-
quickReplyMessage: {}
|
|
983
|
-
});
|
|
984
|
-
}
|
|
985
1042
|
onEventFormSubmit() {
|
|
986
1043
|
this.focusInput();
|
|
987
1044
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
if (!this.props.store.isMobile()) this.focusInput();
|
|
1045
|
+
cancelContainerFocus() {
|
|
1046
|
+
if (this.containerFocusTimer) _index.default.clearTimeout(this.containerFocusTimer);
|
|
1047
|
+
this.containerFocusTimer = null;
|
|
992
1048
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
if (
|
|
998
|
-
|
|
999
|
-
if (this.
|
|
1049
|
+
onContainerClick(event) {
|
|
1050
|
+
this.cancelContainerFocus();
|
|
1051
|
+
const target = event && event.target;
|
|
1052
|
+
const element = target && (target.nodeType === 1 ? target : target.parentElement);
|
|
1053
|
+
if (element && element.closest('a, button, input, textarea, select, [contenteditable]')) return;
|
|
1054
|
+
if (event && event.detail > 1) return;
|
|
1055
|
+
if (this.props.store.isMobile() || window.getSelection()?.toString()) return;
|
|
1056
|
+
const cid = this.props.cid;
|
|
1057
|
+
this.containerFocusTimer = _index.default.setTimeout(() => {
|
|
1058
|
+
this.containerFocusTimer = null;
|
|
1059
|
+
if (!this._isMounted || this.props.cid !== cid || this.props.isShow === false || window.getSelection()?.toString()) return;
|
|
1060
|
+
this.focusInput(undefined, false);
|
|
1061
|
+
}, 300);
|
|
1062
|
+
}
|
|
1063
|
+
startingConversationForm() {
|
|
1064
|
+
const setting = this.props.plugin.chatbox || {};
|
|
1065
|
+
const account = this.props.store.matchAccount() || {};
|
|
1066
|
+
if (this.isOffline(account, setting) && _index.default.get(setting, 'offline_form.enabled')) return setting.offline_form;
|
|
1067
|
+
if (_index.default.get(setting, 'prechat_form.enabled')) return setting.prechat_form;
|
|
1068
|
+
}
|
|
1069
|
+
isFormRequired(cid = this.props.cid) {
|
|
1070
|
+
let form = this.startingConversationForm();
|
|
1000
1071
|
if (!form) return false;
|
|
1001
1072
|
let formData = this.fillForm(form);
|
|
1002
|
-
let convo = this.props.store.matchConvo(
|
|
1073
|
+
let convo = this.props.store.matchConvo(cid) || {};
|
|
1003
1074
|
if (convo.state === 'ended') return true;
|
|
1004
1075
|
if (convo.state && convo.state !== 'pending') delete formData.group;
|
|
1005
1076
|
let isAllFiledEmpty = true;
|
|
1006
1077
|
_index.default.each(formData, field => {
|
|
1007
1078
|
if (field.value) isAllFiledEmpty = false;
|
|
1008
1079
|
});
|
|
1009
|
-
if (isAllFiledEmpty && !this.userHasSent(
|
|
1080
|
+
if (isAllFiledEmpty && !this.userHasSent(cid)) return true;
|
|
1010
1081
|
return !!_index.default.find(formData, field => field.is_required && (field.value == null || field.value === ''));
|
|
1011
1082
|
}
|
|
1012
1083
|
renderConvoSummary(convo) {
|
|
@@ -1151,7 +1222,7 @@ class Widget extends _common.Com {
|
|
|
1151
1222
|
if (form.question_required) {
|
|
1152
1223
|
data['question'] = {
|
|
1153
1224
|
key: 'question',
|
|
1154
|
-
is_required:
|
|
1225
|
+
is_required: false,
|
|
1155
1226
|
label: this.props.t.i18n(_index.default.get(form, `i18n_question_label`, {})) || form.question_label,
|
|
1156
1227
|
type: 'text'
|
|
1157
1228
|
};
|