[IMP] im_livechat, *: Refactor JS Public Livechat (step 5)

*: website_livechat

This commit is a step towards refactoring the JS of public livechat,
so that it reuses the same architecture as the code of Discuss.
This implies code that uses JS models and OWL components.

Task-2894102

closes odoo/odoo#94508

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Alexandre Kühn
2022-06-24 09:26:08 +02:00
parent d420adc877
commit c27de6c738
7 changed files with 286 additions and 100 deletions
@@ -7,7 +7,7 @@ import time from 'web.time';
import utils from 'web.utils';
import LivechatButton from '@im_livechat/legacy/widgets/livechat_button';
import { clear } from '@mail/model/model_field_command';
import { clear, insertAndReplace } from '@mail/model/model_field_command';
const _t = core._t;
const QWeb = core.qweb;
@@ -52,19 +52,14 @@ const QWeb = core.qweb;
const superResult = await this._super(...arguments);
if (this.messaging.livechatButtonView.rule && !!this.messaging.livechatButtonView.rule.chatbot) {
this.messaging.livechatButtonView.update({ isChatbot: true });
this.messaging.livechatButtonView.update({ chatbotState: 'init' });
// noop
} 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.messaging.livechatButtonView.update({ chatbotState: 'welcome' });
}
this.messaging.livechatButtonView.update({ livechatInit: await session.rpc('/im_livechat/init', {channel_id: this.messaging.livechatButtonView.channelId}) });
} else if (this.messaging.livechatButtonView.history !== null && this.messaging.livechatButtonView.history.length !== 0) {
const sessionCookie = utils.get_cookie('im_livechat_session');
if (sessionCookie) {
const sessionKey = 'im_livechat.chatbot.state.uuid_' + JSON.parse(sessionCookie).uuid;
if (localStorage.getItem(sessionKey)) {
this.messaging.livechatButtonView.update({ sessionCookie });
if (localStorage.getItem(this.messaging.livechatButtonView.sessionCookieKey)) {
this.messaging.livechatButtonView.update({ isChatbot: true });
this.messaging.livechatButtonView.update({ chatbotState: 'restore_session' });
}
@@ -74,14 +69,11 @@ const QWeb = core.qweb;
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.messaging.livechatButtonView.update({
chatbotCurrentStep: this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[
this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps.length - 1
],
this.messaging.livechatButtonView.chatbot.update({
currentStep: insertAndReplace({
data: this.messaging.livechatButtonView.chatbot.lastWelcomeStep,
}),
});
}
} else if (this.messaging.livechatButtonView.chatbotState === 'welcome') {
@@ -93,13 +85,11 @@ const QWeb = core.qweb;
utils.set_cookie('im_livechat_auto_popup', '', -1);
this.messaging.livechatButtonView.update({ history: clear() });
this.messaging.livechatButtonView.update({ rule: this.messaging.livechatButtonView.livechatInit.rule });
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.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'));
this._chatbotRestoreSession();
}
return superResult;
@@ -148,7 +138,7 @@ const QWeb = core.qweb;
} else {
this._chatbotSetIsTyping();
this.nextStepTimeout = setTimeout(
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbot.messageDelay);
}
}
},
@@ -176,7 +166,7 @@ const QWeb = core.qweb;
const postedWelcomeMessages = await session.rpc('/chatbot/post_welcome_steps', {
channel_uuid: this.messaging.livechatButtonView.livechat.getUUID(),
chatbot_script_id: this.messaging.livechatButtonView.chatbot.chatbot_script_id,
chatbot_script_id: this.messaging.livechatButtonView.chatbot.data.chatbot_script_id,
});
const welcomeMessagesIds = welcomeMessages.map(welcomeMessage => welcomeMessage._id);
@@ -225,7 +215,7 @@ const QWeb = core.qweb;
$composerTextField.off('keydown', this.chatbotInputKeyDownHandler);
}
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
if (this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'free_input_multi') {
this.chatbotInputKeyDownHandler = this._onChatbotInputKeyDown.bind(this);
$composerTextField.on('keydown', this.chatbotInputKeyDownHandler);
}
@@ -237,7 +227,11 @@ const QWeb = core.qweb;
* @private
*/
_chatbotEndScript() {
if (this.messaging.livechatButtonView.chatbotCurrentStep && this.messaging.livechatButtonView.chatbotCurrentStep.conversation_closed) {
if (
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data &&
this.messaging.livechatButtonView.chatbot.currentStep.data.conversation_closed
) {
// don't touch anything if the user has closed the conversation, let the chat window
// handle the display
return;
@@ -257,9 +251,9 @@ const QWeb = core.qweb;
* @private
*/
_chatbotDisplayRestartButton() {
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));
return this.messaging.livechatButtonView.isChatbot && (!this.messaging.livechatButtonView.chatbot.currentStep ||
(this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type !== 'forward_operator' ||
!this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_operator_found));
},
/**
* Works as a hook since other modules can add their own step types.
@@ -272,7 +266,7 @@ const QWeb = core.qweb;
'question_email',
'free_input_single',
'free_input_multi',
].includes(this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type);
].includes(this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type);
},
/**
* Processes the step, depending on the current state of the script and the author of the last
@@ -304,21 +298,21 @@ const QWeb = core.qweb;
_chatbotProcessStep() {
if (this._chatbotShouldEndScript()) {
this._chatbotEndScript();
} else if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator'
&& this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found) {
} else if (this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'forward_operator'
&& this.messaging.livechatButtonView.chatbot.currentStep.data.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.messaging.livechatButtonView.chatbotMessageDelay);
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbot.messageDelay);
} else {
this._chatbotEnableInput();
}
} else {
let triggerNextStep = true;
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_selection') {
if (this.messaging.livechatButtonView.chatbot.currentStep.data.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
@@ -327,7 +321,7 @@ const QWeb = core.qweb;
}
if (triggerNextStep) {
let nextStepDelay = this.messaging.livechatButtonView.chatbotMessageDelay;
let nextStepDelay = this.messaging.livechatButtonView.chatbot.messageDelay;
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
@@ -359,25 +353,22 @@ const QWeb = core.qweb;
*
* @private
*/
_chatbotRestoreSession(sessionCookie) {
const sessionKey = 'im_livechat.chatbot.state.uuid_' + JSON.parse(sessionCookie).uuid;
_chatbotRestoreSession() {
const browserLocalStorage = window.localStorage;
if (browserLocalStorage && browserLocalStorage.length) {
for (let i = 0; i < browserLocalStorage.length; i++) {
const key = browserLocalStorage.key(i);
if (key.startsWith('im_livechat.chatbot.state.uuid_') && key !== sessionKey) {
if (key.startsWith('im_livechat.chatbot.state.uuid_') && key !== this.messaging.livechatButtonView.sessionCookieKey) {
browserLocalStorage.removeItem(key);
}
}
}
let chatbotState = localStorage.getItem(sessionKey);
let chatbotState = localStorage.getItem(this.messaging.livechatButtonView.sessionCookieKey);
if (chatbotState) {
chatbotState = JSON.parse(chatbotState);
this.messaging.livechatButtonView.update({ isChatbot: true });
this.messaging.livechatButtonView.update({ chatbot: chatbotState._chatbot });
this.messaging.livechatButtonView.update({ chatbotCurrentStep: chatbotState._chatbotCurrentStep });
this.messaging.livechatButtonView.update({ localStorageChatbotState: JSON.parse(chatbotState) });
this.messaging.livechatButtonView.chatbot.update({ currentStep: insertAndReplace({ data: this.messaging.livechatButtonView.localStorageChatbotState._chatbotCurrentStep }) });
}
},
/**
@@ -392,8 +383,8 @@ const QWeb = core.qweb;
_chatbotSaveSession() {
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.messaging.livechatButtonView.chatbotCurrentStep,
'_chatbot': this.messaging.livechatButtonView.chatbot.data,
'_chatbotCurrentStep': this.messaging.livechatButtonView.chatbot.currentStep.data,
}));
},
/**
@@ -415,13 +406,13 @@ const QWeb = core.qweb;
'chatbotImageSrc': `/im_livechat/operator/${
this.messaging.livechatButtonView.livechat.getOperatorPID()[0]
}/avatar`,
'chatbotName': this.messaging.livechatButtonView.chatbot.chatbot_name,
'chatbotName': this.messaging.livechatButtonView.chatbot.name,
'isWelcomeMessage': isWelcomeMessage,
}))
);
this.messaging.livechatButtonView.chatWindow.scrollToBottom();
}, this.messaging.livechatButtonView.chatbotMessageDelay / 3),
}, this.messaging.livechatButtonView.chatbot.messageDelay / 3),
});
},
/**
@@ -439,21 +430,21 @@ const QWeb = core.qweb;
* @private
*/
_chatbotShouldEndScript() {
if (this.messaging.livechatButtonView.chatbotCurrentStep.conversation_closed) {
if (this.messaging.livechatButtonView.chatbot.currentStep.data.conversation_closed) {
return true;
}
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.chatbot.currentStep.data.chatbot_step_is_last &&
(this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type !== 'forward_operator' ||
!this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_operator_found)
) {
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_email'
&& !this.messaging.livechatButtonView.chatbotCurrentStep.is_email_valid
if (this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'question_email'
&& !this.messaging.livechatButtonView.chatbot.currentStep.data.is_email_valid
) {
// email is not (yet) valid, let the user answer / try again
return false;
} else if (
(this._chatbotIsExpectingUserInput() ||
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_selection') &&
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'question_selection') &&
this.messaging.livechatButtonView.messages.length !== 0
) {
const lastMessage = this.messaging.livechatButtonView.messages[this.messaging.livechatButtonView.messages.length - 1];
@@ -489,7 +480,7 @@ const QWeb = core.qweb;
});
if (emailValidResult.success) {
this.messaging.livechatButtonView.chatbotCurrentStep.is_email_valid = true;
this.messaging.livechatButtonView.chatbot.currentStep.data.is_email_valid = true;
this._chatbotSaveSession();
return true;
@@ -511,7 +502,11 @@ const QWeb = core.qweb;
*/
async _chatbotTriggerNextStep() {
let triggerNextStep = true;
if (this.messaging.livechatButtonView.chatbotCurrentStep && this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'question_email') {
if (
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data &&
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'question_email'
) {
triggerNextStep = await this._chatbotValidateEmail();
}
@@ -521,7 +516,7 @@ const QWeb = core.qweb;
const nextStep = await session.rpc('/chatbot/step/trigger', {
channel_uuid:this.messaging.livechatButtonView.livechat.getUUID(),
chatbot_script_id: this.messaging.livechatButtonView.chatbot.chatbot_script_id,
chatbot_script_id: this.messaging.livechatButtonView.chatbot.data.chatbot_script_id,
});
if (nextStep) {
@@ -529,12 +524,12 @@ const QWeb = core.qweb;
this._chatbotAddMessage(nextStep.chatbot_posted_message);
}
this.messaging.livechatButtonView.update({ chatbotCurrentStep: nextStep.chatbot_step });
this.messaging.livechatButtonView.chatbot.update({ currentStep: insertAndReplace({ data: nextStep.chatbot_step }) });
this._chatbotProcessStep();
} else {
// did not find next step -> end the script
this.messaging.livechatButtonView.chatbotCurrentStep['chatbot_step_is_last'] = true;
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_is_last = true;
this._renderMessages();
this._chatbotEndScript();
}
@@ -578,8 +573,12 @@ const QWeb = core.qweb;
_askFeedback() {
this._super(...arguments);
if (this.messaging.livechatButtonView.chatbotCurrentStep) {
this.messaging.livechatButtonView.chatbotCurrentStep.conversation_closed = true;
if (
this.messaging.livechatButtonView.chatbot &&
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data
) {
this.messaging.livechatButtonView.chatbot.currentStep.data.conversation_closed = true;
this._chatbotSaveSession();
}
this.messaging.livechatButtonView.chatWindow.$('.o_livechat_chatbot_main_restart').addClass('d-none');
@@ -607,7 +606,13 @@ const QWeb = core.qweb;
}
});
if (this.messaging.livechatButtonView.chatbotCurrentStep && this.messaging.livechatButtonView.messages && this.messaging.livechatButtonView.messages.length !== 0) {
if (
this.messaging.livechatButtonView.chatbot &&
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data &&
this.messaging.livechatButtonView.messages &&
this.messaging.livechatButtonView.messages.length !== 0
) {
this._chatbotProcessStep();
}
});
@@ -620,7 +625,7 @@ const QWeb = core.qweb;
const parameters = this._super(...arguments);
if (this.messaging.livechatButtonView.isChatbot) {
parameters.chatbot_script_id = this.messaging.livechatButtonView.chatbot.chatbot_script_id;
parameters.chatbot_script_id = this.messaging.livechatButtonView.chatbot.data.chatbot_script_id;
}
return parameters;
@@ -670,7 +675,11 @@ const QWeb = core.qweb;
const superArguments = arguments;
const superMethod = this._super;
if (this.messaging.livechatButtonView.isChatbot && this.messaging.livechatButtonView.chatbotCurrentStep) {
if (
this.messaging.livechatButtonView.isChatbot &&
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data
) {
await this._chatbotPostWelcomeMessages();
}
@@ -679,18 +688,22 @@ const QWeb = core.qweb;
return;
}
if (this.messaging.livechatButtonView.isChatbot && this.messaging.livechatButtonView.chatbotCurrentStep) {
if (
this.messaging.livechatButtonView.isChatbot &&
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data
) {
if (
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator' &&
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_operator_found
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'forward_operator' &&
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_operator_found
) {
return; // operator has taken over the conversation, let them speak
} else if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi') {
} else if (this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'free_input_multi') {
this._debouncedChatbotAwaitUserInput();
} else if (!this._chatbotShouldEndScript()) {
this._chatbotSetIsTyping();
this.nextStepTimeout = setTimeout(
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbot.messageDelay);
} else {
this._chatbotEndScript();
}
@@ -707,7 +720,7 @@ const QWeb = core.qweb;
if (this.messaging.livechatButtonView.isChatbot) {
this._sendWelcomeChatbotMessage(
0,
this.messaging.livechatButtonView.isChatbotBatchWelcomeMessages ? 0 : this.messaging.livechatButtonView.chatbotMessageDelay,
this.messaging.livechatButtonView.isChatbotBatchWelcomeMessages ? 0 : this.messaging.livechatButtonView.chatbot.messageDelay,
);
} else {
this._super(...arguments);
@@ -735,8 +748,8 @@ const QWeb = core.qweb;
* @private
*/
_sendWelcomeChatbotMessage(stepIndex, welcomeMessageDelay) {
const chatbotStep = this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[stepIndex];
this.messaging.livechatButtonView.update({ chatbotCurrentStep: chatbotStep });
const chatbotStep = this.messaging.livechatButtonView.chatbot.welcomeSteps[stepIndex];
this.messaging.livechatButtonView.chatbot.update({ currentStep: insertAndReplace({ data: chatbotStep }) });
if (chatbotStep.chatbot_step_message) {
this._addMessage({
@@ -754,7 +767,7 @@ const QWeb = core.qweb;
});
}
if (stepIndex + 1 < this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps.length) {
if (stepIndex + 1 < this.messaging.livechatButtonView.chatbot.welcomeSteps.length) {
if (welcomeMessageDelay !== 0) {
this._chatbotSetIsTyping(true);
}
@@ -764,7 +777,7 @@ const QWeb = core.qweb;
this._renderMessages();
}, welcomeMessageDelay);
} else {
if (this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'forward_operator') {
if (this.messaging.livechatButtonView.chatbot.currentStep.data.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
@@ -802,23 +815,24 @@ const QWeb = core.qweb;
const postedMessage = await session.rpc('/chatbot/restart', {
channel_uuid: this.messaging.livechatButtonView.livechat.getUUID(),
chatbot_script_id: this.messaging.livechatButtonView.chatbot.chatbot_script_id,
chatbot_script_id: this.messaging.livechatButtonView.chatbot.data.chatbot_script_id,
});
if (postedMessage) {
this._chatbotAddMessage(postedMessage);
}
this.messaging.livechatButtonView.update({ chatbotCurrentStep: clear() });
this.messaging.livechatButtonView.chatbot.update({ currentStep: clear() });
this._chatbotSetIsTyping();
this.nextStepTimeout = setTimeout(
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbotMessageDelay);
this._chatbotTriggerNextStep.bind(this), this.messaging.livechatButtonView.chatbot.messageDelay);
},
_onChatbotInputKeyDown() {
if (
this.messaging.livechatButtonView.chatbotCurrentStep &&
this.messaging.livechatButtonView.chatbotCurrentStep.chatbot_step_type === 'free_input_multi'
this.messaging.livechatButtonView.chatbot.currentStep &&
this.messaging.livechatButtonView.chatbot.currentStep.data &&
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_step_type === 'free_input_multi'
) {
this._debouncedChatbotAwaitUserInput();
}
@@ -863,7 +877,7 @@ const QWeb = core.qweb;
}
const messageId = stepMessage.getID();
stepMessage.setChatbotStepAnswerId(selectedAnswer);
this.messaging.livechatButtonView.chatbotCurrentStep['chatbot_selected_answer_id'] = selectedAnswer;
this.messaging.livechatButtonView.chatbot.currentStep.data.chatbot_selected_answer_id = selectedAnswer;
this._renderMessages();
this._chatbotSaveSession();
@@ -20,10 +20,6 @@ WebsiteLivechatMessage.include({
this._super(...arguments);
if (parent.messaging.livechatButtonView.isChatbot) {
this._chatbotId = parent.messaging.livechatButtonView.chatbot.chatbot_script_id;
this._chatbotName = parent.messaging.livechatButtonView.chatbot.chatbot_name;
this._chatbotOperatorPartnerId = parent.messaging.livechatButtonView.chatbot.chatbot_operator_partner_id;
this._chatbotStepId = data.chatbot_script_step_id;
this._chatbotStepAnswers = data.chatbot_step_answers;
this._chatbotStepAnswerId = data.chatbot_selected_answer_id;
@@ -36,6 +36,7 @@ const LivechatButton = Widget.extend({
this.options = _.defaults(this.messaging.publicLivechatOptions || {});
},
async willStart() {
this.messaging.livechatButtonView.update({ widget: this });
const cookie = utils.get_cookie('im_livechat_session');
if (cookie) {
const channel = JSON.parse(cookie);
@@ -46,7 +47,7 @@ const LivechatButton = Widget.extend({
message.body = utils.Markup(message.body);
}
} else {
const result = await session.rpc('/im_livechat/init', {channel_id: this.options.channel_id});
const result = await session.rpc('/im_livechat/init', {channel_id: this.messaging.livechatButtonView.channelId});
if (!result.available_for_me) {
return Promise.reject();
}
@@ -332,7 +333,7 @@ const LivechatButton = Widget.extend({
*/
_prepareGetSessionParameters() {
return {
channel_id: this.options.channel_id,
channel_id: this.messaging.livechatButtonView.channelId,
anonymous_name: this.messaging.livechatButtonView.defaultUsername,
previous_operator_id: this._get_previous_operator_id(),
};
@@ -0,0 +1,71 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
import { clear } from '@mail/model/model_field_command';
registerModel({
name: 'Chatbot',
identifyingFields: ['livechatButtonViewOwner'],
recordMethods: {
/**
* @private
* @returns {string}
*/
_computeName() {
return this.data.name;
},
/**
* @private
* @returns {Array|FieldCommand}
*/
_computeLastWelcomeStep() {
if (!this.welcomeSteps) {
return clear();
}
return this.welcomeSteps[this.welcomeSteps.length - 1];
},
/**
* @private
* @returns {integer|FieldCommand}
*/
_computeMessageDelay() {
if (this.livechatButtonViewOwner.isWebsiteLivechatChatbotFlow) {
return 100;
}
return clear();
},
/**
* @private
* @returns {Array|FieldCommand}
*/
_computeWelcomeSteps() {
return this.data.chatbot_welcome_steps;
},
},
fields: {
data: attr(),
currentStep: one('ChatbotStep', {
inverse: 'chabotOwner',
isCausal: true,
}),
lastWelcomeStep: attr({
compute: '_computeLastWelcomeStep',
}),
livechatButtonViewOwner: one('LivechatButtonView', {
inverse: 'chatbot',
readonly: true,
required: true,
}),
name: attr({
compute: '_computeName',
}),
messageDelay: attr({
compute: '_computeMessageDelay',
default: 3500, // in milliseconds
}),
welcomeSteps: attr({
compute: '_computeWelcomeSteps',
}),
},
});
@@ -0,0 +1,17 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
registerModel({
name: 'ChatbotStep',
identifyingFields: ['chabotOwner'],
fields: {
chabotOwner: one('Chatbot', {
inverse: 'currentStep',
readonly: true,
required: true,
}),
data: attr(),
},
});
@@ -1,8 +1,8 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr } from '@mail/model/model_field';
import { clear } from '@mail/model/model_field_command';
import { attr, one } from '@mail/model/model_field';
import { clear, insertAndReplace } from '@mail/model/model_field_command';
registerModel({
name: 'LivechatButtonView',
@@ -27,9 +27,35 @@ registerModel({
/**
* @returns {string}
*/
_computeButtonTextColor() {
_computeButtonTextColor() {
return this.messaging.publicLivechatOptions.button_text_color;
},
/**
* @private
* @returns {integer}
*/
_computeChannelId() {
return this.messaging.publicLivechatOptions.channel_id;
},
/**
* @private
* @returns {FieldCommand}
*/
_computeChatbot() {
if (this.isTestChatbot) {
return insertAndReplace({ data: this.testChatbotData.chatbot });
}
if (this.chatbotState === 'init') {
return insertAndReplace({ data: this.rule.chatbot });
}
if (this.chatbotState === 'welcome') {
return insertAndReplace({ data: this.livechatInit.rule.chatbot });
}
if (this.chatbotState === 'restore_session' && this.localStorageChatbotState) {
return insertAndReplace({ data: this.localStorageChatbotState._chatbot });
}
return clear();
},
/**
* @private
* @returns {integer|FieldCommand}
@@ -40,6 +66,19 @@ registerModel({
}
return clear();
},
/**
* @private
* @returns {string|FieldCommand}
*/
_computeChatbotState() {
if (this.rule && !!this.rule.chatbot) {
return 'init';
}
if (this.livechatInit && this.livechatInit.rule.chatbot) {
return 'welcome';
}
return clear();
},
/**
* @private
* @returns {integer}
@@ -92,6 +131,28 @@ registerModel({
}
return this.env._t("Ask something ...");
},
/**
* @private
* @returns {boolean}
*/
_computeIsChatbot() {
if (this.isTestChatbot) {
return true;
}
if (this.rule && this.rule.chatbot) {
return true;
}
if (this.livechatInit && this.livechatInit.rule.chatbot) {
return true;
}
if (this.chatbotState === 'welcome') {
return true;
}
if (this.localStorageChatbotState) {
return true;
}
return clear();
},
/**
* @private
* @returns {string}
@@ -102,6 +163,15 @@ registerModel({
}
return this.messaging.publicLivechatServerUrl;
},
/**
* @returns {string|FieldCommand}
*/
_computeSessionCookieKey() {
if (!this.sessionCookie) {
return clear();
}
return 'im_livechat.chatbot.state.uuid_' + JSON.parse(this.sessionCookie).uuid;
},
/**
* @private
* @returns {string}
@@ -121,13 +191,17 @@ registerModel({
buttonTextColor: attr({
compute: '_computeButtonTextColor',
}),
chatbot: attr(),
chatbotCurrentStep: attr(),
chatbotMessageDelay: attr({
compute: '_computeChatbotMessageDelay',
default: 3500, // in milliseconds
channelId: attr({
compute: '_computeChannelId',
}),
chatbot: one('Chatbot', {
compute: '_computeChatbot',
inverse: 'livechatButtonViewOwner',
isCausal: true,
}),
chatbotState: attr({
compute: '_computeChatbotState',
}),
chatbotState: attr(),
// livechat window
chatWindow: attr({
default: null,
@@ -152,6 +226,7 @@ registerModel({
default: '',
}),
isChatbot: attr({
compute: '_computeIsChatbot',
default: false,
}),
isChatbotBatchWelcomeMessages: attr({
@@ -163,6 +238,9 @@ registerModel({
isOpeningChat: attr({
default: false,
}),
isTestChatbot: attr({
default: false,
}),
isTypingTimeout: attr(),
isWebsiteLivechatChatbotFlow: attr({
default: false,
@@ -172,6 +250,7 @@ registerModel({
default: null,
}),
livechatInit: attr(),
localStorageChatbotState: attr(),
messages: attr({
default: [],
}),
@@ -179,8 +258,14 @@ registerModel({
serverUrl: attr({
compute: '_computeServerUrl',
}),
sessionCookie: attr(),
sessionCookieKey: attr({
compute: '_computeSessionCookieKey',
}),
testChatbotData: attr(),
titleColor: attr({
compute: '_computeTitleColor',
}),
widget: attr(),
},
});
@@ -6,6 +6,8 @@ import utils from 'web.utils';
import LivechatButton from '@im_livechat/legacy/widgets/livechat_button';
import WebsiteLivechat from '@im_livechat/legacy/models/website_livechat';
import { insertAndReplace } from '@mail/model/model_field_command';
/**
* Override of the LivechatButton to create a testing environment for the chatbot script.
*
@@ -26,14 +28,14 @@ const LivechatButtonTestChatbot = LivechatButton.extend({
'auto_popup_timer': 0,
},
});
this.messaging.livechatButtonView.update({ chatbot: chatbotData.chatbot });
this.messaging.livechatButtonView.update({
chatbotCurrentStep: this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps[
this.messaging.livechatButtonView.chatbot.chatbot_welcome_steps.length - 1
],
this.messaging.livechatButtonView.update({ isTestChatbot: true });
this.messaging.livechatButtonView.update({ testChatbotData: chatbotData.chatbot });
this.messaging.livechatButtonView.chatbot.update({
currentStep: insertAndReplace({
data: this.messaging.livechatButtonView.chatbot.lastWelcomeStep,
}),
});
this._channelData = chatbotData.channel;
this.messaging.livechatButtonView.update({ isChatbot: true });
this._channelData = this.messaging.livechatButtonView.testChatbotData.channel;
},
/**