|
|
|
@@ -24,8 +24,6 @@ const QWeb = core.qweb;
|
|
|
|
|
init() {
|
|
|
|
|
this._super(...arguments);
|
|
|
|
|
|
|
|
|
|
this._chatbotMessageDelay = 3500; // in milliseconds
|
|
|
|
|
|
|
|
|
|
// debounced to let the user type several sentences, see '_chatbotAwaitUserInput' for details
|
|
|
|
|
this._debouncedChatbotAwaitUserInput = _.debounce(
|
|
|
|
|
this._chatbotAwaitUserInput.bind(this),
|
|
|
|
@@ -53,17 +51,14 @@ const QWeb = core.qweb;
|
|
|
|
|
async willStart() {
|
|
|
|
|
const superResult = await this._super(...arguments);
|
|
|
|
|
|
|
|
|
|
this.chatbotState = null;
|
|
|
|
|
|
|
|
|
|
if (this.messaging.livechatButtonView.rule && this.messaging.livechatButtonView.rule.chatbot) {
|
|
|
|
|
if (this.messaging.livechatButtonView.rule && !!this.messaging.livechatButtonView.rule.chatbot) {
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbot: true });
|
|
|
|
|
this.chatbotState = 'init';
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotState: 'init' });
|
|
|
|
|
} else if (this.messaging.livechatButtonView.history !== null && this.messaging.livechatButtonView.history.length === 0) {
|
|
|
|
|
this.messaging.livechatButtonView.update({ livechatInit: await session.rpc('/im_livechat/init', {channel_id: this.options.channel_id}) });
|
|
|
|
|
|
|
|
|
|
if (this.messaging.livechatButtonView.livechatInit.rule.chatbot) {
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbot: true });
|
|
|
|
|
this.chatbotState = 'welcome';
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotState: 'welcome' });
|
|
|
|
|
}
|
|
|
|
|
} else if (this.messaging.livechatButtonView.history !== null && this.messaging.livechatButtonView.history.length !== 0) {
|
|
|
|
|
const sessionCookie = utils.get_cookie('im_livechat_session');
|
|
|
|
@@ -71,22 +66,25 @@ const QWeb = core.qweb;
|
|
|
|
|
const sessionKey = 'im_livechat.chatbot.state.uuid_' + JSON.parse(sessionCookie).uuid;
|
|
|
|
|
if (localStorage.getItem(sessionKey)) {
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbot: true });
|
|
|
|
|
this.chatbotState = 'restore_session';
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotState: 'restore_session' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.chatbotState === 'init') {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotState === 'init') {
|
|
|
|
|
// we landed on a website page where a channel rule is configured to run a chatbot.script
|
|
|
|
|
// -> initialize necessary state
|
|
|
|
|
this.messaging.livechatButtonView.update({
|
|
|
|
|
chatbot: this.messaging.livechatButtonView.rule.chatbot,
|
|
|
|
|
});
|
|
|
|
|
if (this.messaging.livechatButtonView.rule.chatbot_welcome_steps && this.messaging.livechatButtonView.rule.chatbot_welcome_steps.length !== 0) {
|
|
|
|
|
this._chatbotCurrentStep = this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[
|
|
|
|
|
this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps.length - 1];
|
|
|
|
|
this.messaging.livechatButtonView.update({
|
|
|
|
|
chatbotCurrentStep: this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[
|
|
|
|
|
this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps.length - 1
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else if (this.chatbotState === 'welcome') {
|
|
|
|
|
} else if (this.messaging.livechatButtonView.chatbotState === 'welcome') {
|
|
|
|
|
// we landed on a website page and a chatbot script was initialized on a previous one
|
|
|
|
|
// however the end-user did not interact with the bot ( :( )
|
|
|
|
|
// -> remove cookie to force opening the popup again
|
|
|
|
@@ -98,7 +96,7 @@ const QWeb = core.qweb;
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbot: this.messaging.livechatButtonView.livechatInit.rule.chatbot });
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbot: true });
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbotBatchWelcomeMessages: true });
|
|
|
|
|
} else if (this.chatbotState === 'restore_session') {
|
|
|
|
|
} else if (this.messaging.livechatButtonView.chatbotState === 'restore_session') {
|
|
|
|
|
// we landed on a website page and a chatbot script is currently running
|
|
|
|
|
// -> restore the user's session (see '_chatbotRestoreSession')
|
|
|
|
|
this._chatbotRestoreSession(utils.get_cookie('im_livechat_session'));
|
|
|
|
@@ -150,7 +148,7 @@ const QWeb = core.qweb;
|
|
|
|
|
} else {
|
|
|
|
|
this._chatbotSetIsTyping();
|
|
|
|
|
this.nextStepTimeout = setTimeout(
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this._chatbotMessageDelay);
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@@ -227,7 +225,7 @@ const QWeb = core.qweb;
|
|
|
|
|
$composerTextField.off('keydown', this.chatbotInputKeyDownHandler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
|
|
|
|
|
this.chatbotInputKeyDownHandler = this._onChatbotInputKeyDown.bind(this);
|
|
|
|
|
$composerTextField.on('keydown', this.chatbotInputKeyDownHandler);
|
|
|
|
|
}
|
|
|
|
@@ -254,9 +252,9 @@ const QWeb = core.qweb;
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
_chatbotDisplayRestartButton() {
|
|
|
|
|
return this.messaging.livechatButtonView.isChatbot && (!this._chatbotCurrentStep ||
|
|
|
|
|
(this._chatbotCurrentStep.chatbot_step_type !== 'forward_operator' ||
|
|
|
|
|
!this._chatbotCurrentStep.chatbot_operator_found));
|
|
|
|
|
return this.messaging.livechatButtonView.isChatbot && (!this.messaging.livechatButtonView.chatbotCurrentStep ||
|
|
|
|
|
(this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type !== 'forward_operator' ||
|
|
|
|
|
!this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found));
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* Works as a hook since other modules can add their own step types.
|
|
|
|
@@ -269,7 +267,7 @@ const QWeb = core.qweb;
|
|
|
|
|
'question_email',
|
|
|
|
|
'free_input_single',
|
|
|
|
|
'free_input_multi',
|
|
|
|
|
].includes(this._chatbotCurrentStep.chatbot_step_type);
|
|
|
|
|
].includes(this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type);
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* Processes the step, depending on the current state of the script and the author of the last
|
|
|
|
@@ -301,21 +299,21 @@ const QWeb = core.qweb;
|
|
|
|
|
_chatbotProcessStep() {
|
|
|
|
|
if (this._chatbotShouldEndScript()) {
|
|
|
|
|
this._chatbotEndScript();
|
|
|
|
|
} else if (this._chatbotCurrentStep.chatbot_step_type === 'forward_operator'
|
|
|
|
|
&& this._chatbotCurrentStep.chatbot_operator_found) {
|
|
|
|
|
} else if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator'
|
|
|
|
|
&& this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found) {
|
|
|
|
|
this._chatbotEnableInput();
|
|
|
|
|
} else if (this._chatbotIsExpectingUserInput()) {
|
|
|
|
|
if (this._isLastMessageFromCustomer()) {
|
|
|
|
|
// user has already typed a message in -> trigger next step
|
|
|
|
|
this._chatbotSetIsTyping();
|
|
|
|
|
this.nextStepTimeout = setTimeout(
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this._chatbotMessageDelay);
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
|
|
|
|
|
} else {
|
|
|
|
|
this._chatbotEnableInput();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let triggerNextStep = true;
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_type === 'question_selection') {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_selection') {
|
|
|
|
|
if (!this._isLastMessageFromCustomer()) {
|
|
|
|
|
// if there is no last message or if the last message is from the bot
|
|
|
|
|
// -> don't trigger the next step, we are waiting for the user to pick an option
|
|
|
|
@@ -324,7 +322,7 @@ const QWeb = core.qweb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (triggerNextStep) {
|
|
|
|
|
let nextStepDelay = this._chatbotMessageDelay;
|
|
|
|
|
let nextStepDelay = this.messaging.livechatButtonView.chatbotMessageDelay;
|
|
|
|
|
if (this.messaging.livechatButtonView.chatWindow.$('.o_livechat_chatbot_typing').length !== 0) {
|
|
|
|
|
// special case where we already have a "is typing" message displayed
|
|
|
|
|
// can happen when the previous step did not trigger any message posted from the bot
|
|
|
|
@@ -374,7 +372,7 @@ const QWeb = core.qweb;
|
|
|
|
|
chatbotState = JSON.parse(chatbotState);
|
|
|
|
|
this.messaging.livechatButtonView.update({ isChatbot: true });
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbot: chatbotState._chatbot });
|
|
|
|
|
this._chatbotCurrentStep = chatbotState._chatbotCurrentStep;
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotCurrentStep: chatbotState._chatbotCurrentStep });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
@@ -390,7 +388,7 @@ const QWeb = core.qweb;
|
|
|
|
|
const chatUuid = this.messaging.livechatButtonView.livechat.toData().uuid;
|
|
|
|
|
localStorage.setItem('im_livechat.chatbot.state.uuid_' + chatUuid, JSON.stringify({
|
|
|
|
|
'_chatbot': this.messaging.livechatButtonView.chatbot,
|
|
|
|
|
'_chatbotCurrentStep': this._chatbotCurrentStep,
|
|
|
|
|
'_chatbotCurrentStep': this.messaging.livechatButtonView.chatbotCurrentStep,
|
|
|
|
|
}));
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
@@ -418,7 +416,7 @@ const QWeb = core.qweb;
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.messaging.livechatButtonView.chatWindow.scrollToBottom();
|
|
|
|
|
}, this._chatbotMessageDelay / 3),
|
|
|
|
|
}, this.messaging.livechatButtonView.chatbotMessageDelay / 3),
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
@@ -434,16 +432,18 @@ const QWeb = core.qweb;
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
_chatbotShouldEndScript() {
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_is_last &&
|
|
|
|
|
(this._chatbotCurrentStep.chatbot_step_type !== 'forward_operator' ||
|
|
|
|
|
!this._chatbotCurrentStep.chatbot_operator_found)) {
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_type === 'question_email'
|
|
|
|
|
&& !this._chatbotCurrentStep.is_email_valid) {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_is_last &&
|
|
|
|
|
(this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type !== 'forward_operator' ||
|
|
|
|
|
!this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found)
|
|
|
|
|
) {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_email'
|
|
|
|
|
&& !this.messaging.livechatButtonView.chatbotCurrentStep.is_email_valid
|
|
|
|
|
) {
|
|
|
|
|
// email is not (yet) valid, let the user answer / try again
|
|
|
|
|
return false;
|
|
|
|
|
} else if (
|
|
|
|
|
(this._chatbotIsExpectingUserInput() ||
|
|
|
|
|
this._chatbotCurrentStep.chatbot_step_type === 'question_selection') &&
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_selection') &&
|
|
|
|
|
this.messaging.livechatButtonView.messages.length !== 0
|
|
|
|
|
) {
|
|
|
|
|
const lastMessage = this.messaging.livechatButtonView.messages[this.messaging.livechatButtonView.messages.length - 1];
|
|
|
|
@@ -479,7 +479,7 @@ const QWeb = core.qweb;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (emailValidResult.success) {
|
|
|
|
|
this._chatbotCurrentStep.is_email_valid = true;
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep.is_email_valid = true;
|
|
|
|
|
this._chatbotSaveSession();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
@@ -501,7 +501,7 @@ const QWeb = core.qweb;
|
|
|
|
|
*/
|
|
|
|
|
async _chatbotTriggerNextStep() {
|
|
|
|
|
let triggerNextStep = true;
|
|
|
|
|
if (this._chatbotCurrentStep && this._chatbotCurrentStep.chatbot_step_type === 'question_email') {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep && this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_email') {
|
|
|
|
|
triggerNextStep = await this._chatbotValidateEmail();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -519,12 +519,12 @@ const QWeb = core.qweb;
|
|
|
|
|
this._chatbotAddMessage(nextStep.chatbot_posted_message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._chatbotCurrentStep = nextStep.chatbot_step;
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotCurrentStep: nextStep.chatbot_step });
|
|
|
|
|
|
|
|
|
|
this._chatbotProcessStep();
|
|
|
|
|
} else {
|
|
|
|
|
// did not find next step -> end the script
|
|
|
|
|
this._chatbotCurrentStep['chatbot_step_is_last'] = true;
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep['chatbot_step_is_last'] = true;
|
|
|
|
|
this._renderMessages();
|
|
|
|
|
this._chatbotEndScript();
|
|
|
|
|
}
|
|
|
|
@@ -593,7 +593,7 @@ const QWeb = core.qweb;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (this._chatbotCurrentStep && this.messaging.livechatButtonView.messages && this.messaging.livechatButtonView.messages.length !== 0) {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep && this.messaging.livechatButtonView.messages && this.messaging.livechatButtonView.messages.length !== 0) {
|
|
|
|
|
this._chatbotProcessStep();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
@@ -656,7 +656,7 @@ const QWeb = core.qweb;
|
|
|
|
|
const superArguments = arguments;
|
|
|
|
|
const superMethod = this._super;
|
|
|
|
|
|
|
|
|
|
if (this.messaging.livechatButtonView.isChatbot && this._chatbotCurrentStep) {
|
|
|
|
|
if (this.messaging.livechatButtonView.isChatbot && this.messaging.livechatButtonView.chatbotCurrentStep) {
|
|
|
|
|
await this._chatbotPostWelcomeMessages();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -665,16 +665,18 @@ const QWeb = core.qweb;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.messaging.livechatButtonView.isChatbot && this._chatbotCurrentStep) {
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_type === 'forward_operator' &&
|
|
|
|
|
this._chatbotCurrentStep.chatbot_operator_found) {
|
|
|
|
|
if (this.messaging.livechatButtonView.isChatbot && this.messaging.livechatButtonView.chatbotCurrentStep) {
|
|
|
|
|
if (
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator' &&
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found
|
|
|
|
|
) {
|
|
|
|
|
return; // operator has taken over the conversation, let them speak
|
|
|
|
|
} else if (this._chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
|
|
|
|
|
} else if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
|
|
|
|
|
this._debouncedChatbotAwaitUserInput();
|
|
|
|
|
} else if (!this._chatbotShouldEndScript()) {
|
|
|
|
|
this._chatbotSetIsTyping();
|
|
|
|
|
this.nextStepTimeout = setTimeout(
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this._chatbotMessageDelay);
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
|
|
|
|
|
} else {
|
|
|
|
|
this._chatbotEndScript();
|
|
|
|
|
}
|
|
|
|
@@ -691,7 +693,7 @@ const QWeb = core.qweb;
|
|
|
|
|
if (this.messaging.livechatButtonView.isChatbot) {
|
|
|
|
|
this._sendWelcomeChatbotMessage(
|
|
|
|
|
0,
|
|
|
|
|
this.messaging.livechatButtonView.isChatbotBatchWelcomeMessages ? 0 : this._chatbotMessageDelay,
|
|
|
|
|
this.messaging.livechatButtonView.isChatbotBatchWelcomeMessages ? 0 : this.messaging.livechatButtonView.chatbotMessageDelay,
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
this._super(...arguments);
|
|
|
|
@@ -720,7 +722,7 @@ const QWeb = core.qweb;
|
|
|
|
|
*/
|
|
|
|
|
_sendWelcomeChatbotMessage(stepIndex, welcomeMessageDelay) {
|
|
|
|
|
const chatbotStep = this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[stepIndex];
|
|
|
|
|
this._chatbotCurrentStep = chatbotStep;
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotCurrentStep: chatbotStep });
|
|
|
|
|
|
|
|
|
|
if (chatbotStep.chatbot_step_message) {
|
|
|
|
|
this._addMessage({
|
|
|
|
@@ -748,7 +750,7 @@ const QWeb = core.qweb;
|
|
|
|
|
this._renderMessages();
|
|
|
|
|
}, welcomeMessageDelay);
|
|
|
|
|
} else {
|
|
|
|
|
if (this._chatbotCurrentStep.chatbot_step_type === 'forward_operator') {
|
|
|
|
|
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator') {
|
|
|
|
|
// special case when the last welcome message is a forward to an operator
|
|
|
|
|
// we need to save the welcome messages before continuing the script
|
|
|
|
|
// indeed, if there are no operator available, the script will continue
|
|
|
|
@@ -793,15 +795,17 @@ const QWeb = core.qweb;
|
|
|
|
|
this._chatbotAddMessage(postedMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._chatbotCurrentStep = null;
|
|
|
|
|
this.messaging.livechatButtonView.update({ chatbotCurrentStep: clear() });
|
|
|
|
|
this._chatbotSetIsTyping();
|
|
|
|
|
this.nextStepTimeout = setTimeout(
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this._chatbotMessageDelay);
|
|
|
|
|
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_onChatbotInputKeyDown() {
|
|
|
|
|
if (this._chatbotCurrentStep &&
|
|
|
|
|
this._chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
|
|
|
|
|
if (
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep &&
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi'
|
|
|
|
|
) {
|
|
|
|
|
this._debouncedChatbotAwaitUserInput();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@@ -845,7 +849,7 @@ const QWeb = core.qweb;
|
|
|
|
|
}
|
|
|
|
|
const messageId = stepMessage.getID();
|
|
|
|
|
stepMessage.setChatbotStepAnswerId(selectedAnswer);
|
|
|
|
|
this._chatbotCurrentStep['chatbot_selected_answer_id'] = selectedAnswer;
|
|
|
|
|
this.messaging.livechatButtonView.chatbotCurrentStep['chatbot_selected_answer_id'] = selectedAnswer;
|
|
|
|
|
this._renderMessages();
|
|
|
|
|
this._chatbotSaveSession();
|
|
|
|
|
|
|
|
|
|