diff --git a/addons/im_livechat/__manifest__.py b/addons/im_livechat/__manifest__.py index 2fa02db7da9..c0f7a37666e 100644 --- a/addons/im_livechat/__manifest__.py +++ b/addons/im_livechat/__manifest__.py @@ -54,7 +54,6 @@ Help your customers with this chat, and analyse their feedback. 'im_livechat/static/src/services/*.js', 'im_livechat/static/src/legacy/public_livechat_history_tracking.js', 'im_livechat/static/src/legacy/public_livechat_chatbot.js', - 'im_livechat/static/src/legacy/public_livechat_message_chatbot.js', 'im_livechat/static/src/legacy/public_livechat.scss', 'im_livechat/static/src/legacy/public_livechat_chatbot.scss', ], @@ -77,7 +76,6 @@ Help your customers with this chat, and analyse their feedback. 'im_livechat/static/tests/qunit_suite_tests/components/**/*.js', 'im_livechat/static/src/legacy/public_livechat_history_tracking.js', 'im_livechat/static/src/legacy/public_livechat_chatbot.js', - 'im_livechat/static/src/legacy/public_livechat_message_chatbot.js', ], 'web.assets_tests': [ 'im_livechat/static/tests/tours/**/*', @@ -189,7 +187,6 @@ Help your customers with this chat, and analyse their feedback. 'mail/static/src/js/utils.js', 'im_livechat/static/src/legacy/public_livechat_history_tracking.js', 'im_livechat/static/src/legacy/public_livechat_chatbot.js', - 'im_livechat/static/src/legacy/public_livechat_message_chatbot.js', ('include', 'web._assets_helpers'), diff --git a/addons/im_livechat/static/src/legacy/models/public_livechat.js b/addons/im_livechat/static/src/legacy/models/public_livechat.js index 4f1b70872ab..097060295ad 100644 --- a/addons/im_livechat/static/src/legacy/models/public_livechat.js +++ b/addons/im_livechat/static/src/legacy/models/public_livechat.js @@ -16,8 +16,8 @@ import { sprintf } from 'web.utils'; */ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { /** - * @override * @private + * @param {Messaging} messaging * @param {Object} params * @param {Object} params.data * @param {boolean} [params.data.folded] states whether the livechat is @@ -34,15 +34,15 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { * @param {string} params.data.uuid the UUID of this livechat. * @param {@im_livechat/legacy/widgets/livechat_button} params.parent */ - init(params) { + init(messaging, params) { Mixins.EventDispatcherMixin.init.call(this, arguments); this.setParent(params.parent); + this.messaging = messaging; this._folded = false; // threads are unfolded by default this._id = params.data.id; this._name = params.data.name; this._status = params.data.status || ''; - this._unreadCounter = 0; // amount of messages not yet been read /** * Initialize the internal data for typing feature on threads. @@ -123,7 +123,9 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { this._uuid = params.data.uuid; if (params.data.message_unread_counter !== undefined) { - this._unreadCounter = params.data.message_unread_counter; + this.messaging.livechatButtonView.publicLivechat.update({ + unreadCounter: params.data.message_unread_counter + }); } if (_.isBoolean(params.data.folded)) { @@ -232,8 +234,8 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { * @returns {Promise} */ markAsRead() { - if (this._unreadCounter > 0) { - this._unreadCounter = 0; + if (this.messaging.livechatButtonView.publicLivechat.unreadCounter > 0) { + this.messaging.livechatButtonView.publicLivechat.update({ unreadCounter: 0 }); this.trigger_up('updated_unread_counter'); return Promise.resolve(); } @@ -302,7 +304,7 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { return { folded: this._folded, id: this._id, - message_unread_counter: this._unreadCounter, + message_unread_counter: this.messaging.livechatButtonView.publicLivechat.unreadCounter, operator_pid: this._operatorPID, name: this._name, uuid: this._uuid, diff --git a/addons/im_livechat/static/src/legacy/models/public_livechat_message.js b/addons/im_livechat/static/src/legacy/models/public_livechat_message.js index f35889065e2..90026ed771d 100644 --- a/addons/im_livechat/static/src/legacy/models/public_livechat_message.js +++ b/addons/im_livechat/static/src/legacy/models/public_livechat_message.js @@ -52,6 +52,12 @@ const PublicLivechatMessage = Class.extend({ }); this._defaultUsername = options.default_username; this._serverURL = options.serverURL; + + if (parent.messaging.livechatButtonView.isChatbot) { + this._chatbotStepId = data.chatbot_script_step_id; + this._chatbotStepAnswers = data.chatbot_step_answers; + this._chatbotStepAnswerId = data.chatbot_selected_answer_id; + } }, //-------------------------------------------------------------------------- @@ -109,6 +115,24 @@ const PublicLivechatMessage = Class.extend({ getBody() { return this._body; }, + /** + * @return {string} + */ + getChatbotStepId() { + return this._chatbotStepId; + }, + /** + * @return {string} + */ + getChatbotStepAnswers() { + return this._chatbotStepAnswers; + }, + /** + * @return {string} + */ + getChatbotStepAnswerId() { + return this._chatbotStepAnswerId; + }, /** * @return {moment} */ @@ -408,6 +432,9 @@ const PublicLivechatMessage = Class.extend({ return _.contains(attachmentIDs, attachment.id); }); }, + setChatbotStepAnswerId(chatbotStepAnswerId) { + this._chatbotStepAnswerId = chatbotStepAnswerId; + }, /** * State whether this message should redirect to the author * when clicking on the author of this message. diff --git a/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js b/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js index 23dfb88fe33..96a5af9ac29 100644 --- a/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js +++ b/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js @@ -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, insertAndReplace } from '@mail/model/model_field_command'; +import { clear, increment, insertAndReplace } from '@mail/model/model_field_command'; const _t = core._t; const QWeb = core.qweb; @@ -59,8 +59,7 @@ const QWeb = core.qweb; const sessionCookie = utils.get_cookie('im_livechat_session'); if (sessionCookie) { this.messaging.livechatButtonView.update({ sessionCookie }); - if (localStorage.getItem(this.messaging.livechatButtonView.sessionCookieKey)) { - this.messaging.livechatButtonView.update({ isChatbot: true }); + if (localStorage.getItem(this.messaging.livechatButtonView.chatbotSessionCookieKey)) { this.messaging.livechatButtonView.update({ chatbotState: 'restore_session' }); } } @@ -108,8 +107,8 @@ const QWeb = core.qweb; _chatbotAddMessage(message, options) { message.body = utils.Markup(message.body); this._addMessage(message, options); - if (this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isFolded() || !this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isAtBottom()) { - this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat._unreadCounter++; + if (this.messaging.livechatButtonView.chatWindow.legacyChatWindow._thread._folded || !this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.isAtBottom()) { + this.messaging.livechatButtonView.publicLivechat.update({ unreadCounter: increment() }); } if (!options || !options.skipRenderMessages) { @@ -357,13 +356,13 @@ const QWeb = core.qweb; 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 !== this.messaging.livechatButtonView.sessionCookieKey) { + if (key.startsWith('im_livechat.chatbot.state.uuid_') && key !== this.messaging.livechatButtonView.chatbotSessionCookieKey) { browserLocalStorage.removeItem(key); } } } - let chatbotState = localStorage.getItem(this.messaging.livechatButtonView.sessionCookieKey); + let chatbotState = localStorage.getItem(this.messaging.livechatButtonView.chatbotSessionCookieKey); if (chatbotState) { this.messaging.livechatButtonView.chatbot.update({ currentStep: insertAndReplace({ data: this.messaging.livechatButtonView.localStorageChatbotState._chatbotCurrentStep }) }); @@ -408,7 +407,7 @@ const QWeb = core.qweb; })) ); - this.messaging.livechatButtonView.chatWindow.legacyChatWindow.scrollToBottom(); + this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.scrollToBottom(); }, this.messaging.livechatButtonView.chatbot.messageDelay / 3), }); }, @@ -599,7 +598,7 @@ const QWeb = core.qweb; return this._super(...arguments).then(() => { window.addEventListener('resize', () => { if (this.messaging.livechatButtonView.chatWindow) { - this.messaging.livechatButtonView.chatWindow.legacyChatWindow.scrollToBottom(); + this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.scrollToBottom(); } }); diff --git a/addons/im_livechat/static/src/legacy/public_livechat_message_chatbot.js b/addons/im_livechat/static/src/legacy/public_livechat_message_chatbot.js deleted file mode 100644 index 7806ed3c9dd..00000000000 --- a/addons/im_livechat/static/src/legacy/public_livechat_message_chatbot.js +++ /dev/null @@ -1,65 +0,0 @@ -/** @odoo-module **/ - -import PublicLivechatMessage from '@im_livechat/legacy/models/public_livechat_message'; - -/** - * Override of the PublicLivechatMessage that includes chatbot capabilities. - * The main changes are: - * - Allow to display options for the end-user to click on ("_chatbotStepAnswers") - * - Show a different name/icon for the chatbot (instead of the 'OdooBot' operator name/icon) - */ -PublicLivechatMessage.include({ - /** - * @param {@im_livechat/legacy/widgets/livechat_button} parent - * @param {Object} data - * @param {Object} options - * @param {string} options.default_username - * @param {string} options.serverURL - */ - init(parent, data, options) { - this._super(...arguments); - - if (parent.messaging.livechatButtonView.isChatbot) { - this._chatbotStepId = data.chatbot_script_step_id; - this._chatbotStepAnswers = data.chatbot_step_answers; - this._chatbotStepAnswerId = data.chatbot_selected_answer_id; - } - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * Get chat bot script step ID - * - * @return {string} - */ - getChatbotStepId() { - return this._chatbotStepId; - }, - /** - * Get chat bot script answers - * - * @return {string} - */ - getChatbotStepAnswers() { - return this._chatbotStepAnswers; - }, - /** - * Get chat bot script answer ID - * - * @return {string} - */ - getChatbotStepAnswerId() { - return this._chatbotStepAnswerId; - }, - /** - * @override - */ - setChatbotStepAnswerId(chatbotStepAnswerId) { - this._chatbotStepAnswerId = chatbotStepAnswerId; - } -}); - -export default PublicLivechatMessage; diff --git a/addons/im_livechat/static/src/legacy/widgets/livechat_button.js b/addons/im_livechat/static/src/legacy/widgets/livechat_button.js index fc95ea0e9ca..3e00f16faa7 100644 --- a/addons/im_livechat/static/src/legacy/widgets/livechat_button.js +++ b/addons/im_livechat/static/src/legacy/widgets/livechat_button.js @@ -11,7 +11,7 @@ import { LIVECHAT_COOKIE_HISTORY } from 'im_livechat.legacy.im_livechat.Constant import Feedback from '@im_livechat/legacy/widgets/feedback/feedback'; import PublicLivechatMessage from '@im_livechat/legacy/models/public_livechat_message'; -import { clear, insertAndReplace } from '@mail/model/model_field_command'; +import { clear, increment, insert, insertAndReplace } from '@mail/model/model_field_command'; const _t = core._t; const QWeb = core.qweb; @@ -31,7 +31,7 @@ const LivechatButton = Widget.extend({ init(parent, messaging) { this._super(parent); this.messaging = messaging; - this.options = _.defaults(this.messaging.publicLivechatOptions || {}); + this.options = _.defaults(this.messaging.publicLivechatGlobal.options || {}); }, async willStart() { this.messaging.livechatButtonView.update({ widget: this }); @@ -107,6 +107,14 @@ const LivechatButton = Widget.extend({ if (hasAlreadyMessage) { return; } + if (this.messaging.livechatButtonView.publicLivechat) { + this.messaging.livechatButtonView.publicLivechat.update({ + messages: insert({ + id: data.id, + legacyPublicLivechatMessage: message, + }), + }); + } if (this.messaging.livechatButtonView.publicLivechat && this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat) { this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat.addMessage(message); @@ -189,8 +197,8 @@ const LivechatButton = Widget.extend({ } notificationData.body = utils.Markup(notificationData.body); this._addMessage(notificationData); - if (this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isFolded() || !this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isAtBottom()) { - this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat._unreadCounter++; + if (this.messaging.livechatButtonView.chatWindow.legacyChatWindow._thread._folded || !this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.isAtBottom()) { + this.messaging.livechatButtonView.publicLivechat.update({ unreadCounter: increment() }); } this._renderMessages(); return; @@ -329,11 +337,11 @@ const LivechatButton = Widget.extend({ * @private */ _renderMessages() { - const shouldScroll = !this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isFolded() && this.messaging.livechatButtonView.chatWindow.legacyChatWindow.isAtBottom(); + const shouldScroll = !this.messaging.livechatButtonView.chatWindow.legacyChatWindow._thread._folded && this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.isAtBottom(); this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat._messages = this.messaging.livechatButtonView.messages; this.messaging.livechatButtonView.chatWindow.legacyChatWindow.render(); if (shouldScroll) { - this.messaging.livechatButtonView.chatWindow.legacyChatWindow.scrollToBottom(); + this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.scrollToBottom(); } }, /** @@ -365,7 +373,7 @@ const LivechatButton = Widget.extend({ } this._closeChat(); } - this.messaging.livechatButtonView.chatWindow.legacyChatWindow.scrollToBottom(); + this.messaging.livechatButtonView.chatWindow.legacyChatWindow._publicLivechatView.scrollToBottom(); }); }, /** diff --git a/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.js b/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.js index ac16e0e2a1b..da9f4e3d815 100644 --- a/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.js +++ b/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import ThreadWidget from '@im_livechat/legacy/widgets/thread/thread'; +import PublicLivechatView from '@im_livechat/legacy/widgets/thread/thread'; import config from 'web.config'; import { _t, qweb } from 'web.core'; @@ -30,23 +30,19 @@ const PublicLivechatWindow = Widget.extend({ }, /** * @param {Widget} parent + * @param {Messaging} messaging * @param {@im_livechat/legacy/models/public_livechat} thread * @param {Object} [options={}] * @param {string} [options.headerBackgroundColor] * @param {string} [options.titleColor] */ - init(parent, thread, options) { + init(parent, messaging, thread, options) { this._super(parent); - + this.messaging = messaging; this.options = _.defaults(options || {}, { - autofocus: true, - displayStars: true, - displayReplyIcons: false, - displayNotificationIcons: false, placeholder: _t("Say something"), }); - this._hidden = false; this._thread = thread; this._debouncedOnScroll = _.debounce(this._onScroll.bind(this), 100); @@ -60,26 +56,25 @@ const PublicLivechatWindow = Widget.extend({ this.$header = this.$('.o_thread_window_header'); const options = { displayMarkAsRead: false, - displayStars: this.options.displayStars, }; if (this._thread && this._thread._type === 'document_thread') { options.displayDocumentLinks = false; } - this._threadWidget = new ThreadWidget(this, options); + this._publicLivechatView = new PublicLivechatView(this, this.messaging, options); // animate the (un)folding of thread windows this.$el.css({ transition: 'height ' + this.FOLD_ANIMATION_DURATION + 'ms linear' }); - if (this.isFolded()) { + if (this._thread._folded) { this.$el.css('height', this.HEIGHT_FOLDED); - } else if (this.options.autofocus) { + } else { this._focusInput(); } if (!config.device.isMobile) { const margin_dir = _t.database.parameters.direction === "rtl" ? "margin-left" : "margin-right"; this.$el.css(margin_dir, $.position.scrollbarWidth()); } - const def = this._threadWidget.replace(this.$('.o_thread_window_content')).then(() => { - this._threadWidget.$el.on('scroll', this, this._debouncedOnScroll); + const def = this._publicLivechatView.replace(this.$('.o_thread_window_content')).then(() => { + this._publicLivechatView.$el.on('scroll', this, this._debouncedOnScroll); }); await Promise.all([this._super(), def]); if (this.options.headerBackgroundColor) { @@ -89,27 +84,6 @@ const PublicLivechatWindow = Widget.extend({ this.$('.o_thread_window_header').css('color', this.options.titleColor); } }, - /** - * @override - */ - do_hide() { - this._hidden = true; - this._super(...arguments); - }, - /** - * @override - */ - do_show() { - this._hidden = false; - this._super(...arguments); - }, - /** - * @override - */ - do_toggle(display) { - this._hidden = _.isBoolean(display) ? !display : !this._hidden; - this._super(...arguments); - }, //-------------------------------------------------------------------------- @@ -122,51 +96,6 @@ const PublicLivechatWindow = Widget.extend({ close() { this.trigger_up('close_chat_window'); }, - /** - * Get the title of the thread window, which usually contains the name of - * the thread. - * - * @returns {string} - */ - getTitle() { - return this._thread._name; - }, - /** - * Get the unread counter of the related thread. If there are no thread - * linked to this window, returns 0. - * - * @returns {integer} - */ - getUnreadCounter() { - return this._thread._unreadCounter; - }, - /** - * Tells whether the bottom of the thread in the thread window is visible - * or not. - * - * @returns {boolean} - */ - isAtBottom() { - return this._threadWidget.isAtBottom(); - }, - /** - * State whether the related thread is folded or not. If there are no - * thread related to this window, it means this is the "blank" thread - * window, therefore we use the internal folded state. - * - * @returns {boolean} - */ - isFolded() { - return this._thread._folded; - }, - /** - * States whether the thread window is hidden or not. - * - * @returns {boolean} - */ - isHidden() { - return this._hidden; - }, /** * States whether the current environment is in mobile or not. This is * useful in order to customize the template rendering for mobile view. @@ -176,21 +105,12 @@ const PublicLivechatWindow = Widget.extend({ isMobile() { return config.device.isMobile; }, - /** - * States whether the input of the thread window should be displayed or not. - * By default, any thread window with a thread needs a composer. - * - * @returns {boolean} - */ - needsComposer() { - return true; - }, /** * Render the thread window */ render() { this.renderHeader(); - this._threadWidget.render(this._thread, { displayLoadMore: false }); + this._publicLivechatView.render(this._thread, { displayLoadMore: false }); }, /** * Render the header of this thread window. @@ -200,9 +120,15 @@ const PublicLivechatWindow = Widget.extend({ * @private */ renderHeader() { - const options = this._getHeaderRenderingOptions(); this.$header.html( - qweb.render('im_livechat.legacy.PublicLivechatWindow.HeaderContent', options)); + qweb.render('im_livechat.legacy.PublicLivechatWindow.HeaderContent', { + status: this._thread._status, + thread: this._thread, + title: this._thread._name, + unreadCounter: this.messaging.livechatButtonView.publicLivechat.unreadCounter, + widget: this, + }) + ); }, /** * Replace the thread content with provided new content @@ -210,13 +136,7 @@ const PublicLivechatWindow = Widget.extend({ * @param {$.Element} $element */ replaceContentWith($element) { - $element.replace(this._threadWidget.$el); - }, - /** - * Scroll to the bottom of the thread in the thread window - */ - scrollToBottom() { - this._threadWidget.scrollToBottom(); + $element.replace(this._publicLivechatView.$el); }, /** * Toggle the fold state of this thread window. Also update the fold state @@ -230,7 +150,7 @@ const PublicLivechatWindow = Widget.extend({ */ toggleFold(folded) { if (!_.isBoolean(folded)) { - folded = !this.isFolded(); + folded = !this._thread._folded; } this._updateThreadFoldState(folded); this.trigger_up('save_chat_window'); @@ -242,13 +162,11 @@ const PublicLivechatWindow = Widget.extend({ * that has been changed. */ updateVisualFoldState() { - if (!this.isFolded()) { - this._threadWidget.scrollToBottom(); - if (this.options.autofocus) { - this._focusInput(); - } + if (!this._thread._folded) { + this._publicLivechatView.scrollToBottom(); + this._focusInput(); } - const height = this.isFolded() ? this.HEIGHT_FOLDED : this.HEIGHT_OPEN; + const height = this._thread._folded ? this.HEIGHT_FOLDED : this.HEIGHT_OPEN; this.$el.css({ height }); }, @@ -272,21 +190,6 @@ const PublicLivechatWindow = Widget.extend({ } this.$input.focus(); }, - /** - * Returns the options used by the rendering of the window's header - * - * @private - * @returns {Object} - */ - _getHeaderRenderingOptions() { - return { - status: this._thread._status, - thread: this._thread, - title: this.getTitle(), - unreadCounter: this.getUnreadCounter(), - widget: this, - }; - }, /** * Tells whether there is focus on this thread. Note that a thread that has * the focus means the input has focus. @@ -308,7 +211,7 @@ const PublicLivechatWindow = Widget.extend({ this.trigger_up('post_message_chat_window', { messageData }); this._thread.postMessage(messageData) .then(() => { - this._threadWidget.scrollToBottom(); + this._publicLivechatView.scrollToBottom(); }); }, /** @@ -340,8 +243,8 @@ const PublicLivechatWindow = Widget.extend({ ev.stopPropagation(); ev.preventDefault(); if ( - this._thread._unreadCounter > 0 && - !this.isFolded() + this.messaging.livechatButtonView.publicLivechat.unreadCounter > 0 && + !this._thread._folded ) { this._thread.markAsRead(); } @@ -419,7 +322,7 @@ const PublicLivechatWindow = Widget.extend({ * @private */ _onScroll() { - if (this.isAtBottom()) { + if (this._publicLivechatView.isAtBottom()) { this._thread.markAsRead(); } }, diff --git a/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.xml b/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.xml index d72884a1832..59fa678ace4 100644 --- a/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.xml +++ b/addons/im_livechat/static/src/legacy/widgets/public_livechat_window/public_livechat_window.xml @@ -8,14 +8,14 @@
- - + +
-
+
diff --git a/addons/im_livechat/static/src/legacy/widgets/thread/thread.js b/addons/im_livechat/static/src/legacy/widgets/thread/thread.js index 2cd7b1345d2..247919e9a53 100644 --- a/addons/im_livechat/static/src/legacy/widgets/thread/thread.js +++ b/addons/im_livechat/static/src/legacy/widgets/thread/thread.js @@ -23,7 +23,7 @@ const READ_LESS = _lt("read less"); * Any thread that extends mail.model.AbstractThread can be used with this * widget. */ -const ThreadWidget = Widget.extend({ +const PublicLivechatView = Widget.extend({ className: 'o_mail_thread', events: { @@ -48,10 +48,12 @@ const ThreadWidget = Widget.extend({ /** * @override * @param {widget} parent + * @param {Messaging} messaging * @param {Object} options */ - init(parent, options) { + init(parent, messaging, options) { this._super(...arguments); + this.messaging = messaging; this.attachments = []; // options when the thread is enabled (e.g. can send message, // interact on messages, etc.) @@ -59,12 +61,9 @@ const ThreadWidget = Widget.extend({ displayOrder: ORDER.ASC, displayMarkAsRead: true, displayModerationCommands: false, - displayStars: true, displayDocumentLinks: true, displayAvatars: true, squashCloseMessages: true, - displayNotificationIcons: true, - displayReplyIcons: false, loadMoreOnScroll: false, hasMessageAttachmentDeletable: false, }); @@ -73,12 +72,9 @@ const ThreadWidget = Widget.extend({ displayOrder: this._enabledOptions.displayOrder, displayMarkAsRead: false, displayModerationCommands: false, - displayStars: false, displayDocumentLinks: false, displayAvatars: this._enabledOptions.displayAvatars, squashCloseMessages: false, - displayNotificationIcons: false, - displayReplyIcons: false, loadMoreOnScroll: this._enabledOptions.loadMoreOnScroll, hasMessageAttachmentDeletable: false, }; @@ -613,6 +609,6 @@ const ThreadWidget = Widget.extend({ }, }); -ThreadWidget.ORDER = ORDER; +PublicLivechatView.ORDER = ORDER; -export default ThreadWidget; +export default PublicLivechatView; diff --git a/addons/im_livechat/static/src/legacy/widgets/thread/thread.xml b/addons/im_livechat/static/src/legacy/widgets/thread/thread.xml index a7157f20869..08cfa0d1b8b 100644 --- a/addons/im_livechat/static/src/legacy/widgets/thread/thread.xml +++ b/addons/im_livechat/static/src/legacy/widgets/thread/thread.xml @@ -127,12 +127,9 @@ @param {Object} options @param {boolean} [options.displayAvatars] @param {boolean} [options.displayDocumentLinks] - @param {boolean} [options.displayNotificationIcons] @param {boolean} [options.displayMarkAsRead] @param {boolean} [options.displayModerationCommands] when set, display the moderation commands on the message. This includes the moderation checkboxes (needs a control panel such as in Discuss app). - @param {boolean} [options.displayReplyIcons] - @param {boolean} [options.displayStars] @param {boolean} [options.displaySubjectsOnMessages] @param {boolean} options.hasMessageAttachmentDeletable @param {string|integer} [options.messagesSeparatorPosition] 'top' or @@ -165,9 +162,6 @@ -

@@ -196,16 +190,7 @@ (from #) - - - - - - - diff --git a/addons/im_livechat/static/src/models/livechat_button_view.js b/addons/im_livechat/static/src/models/livechat_button_view.js index 57f34071b0f..9e5c78c7a8b 100644 --- a/addons/im_livechat/static/src/models/livechat_button_view.js +++ b/addons/im_livechat/static/src/models/livechat_button_view.js @@ -13,14 +13,14 @@ registerModel({ * @returns {string} */ _computeButtonBackgroundColor() { - return this.messaging.publicLivechatOptions.button_background_color; + return this.messaging.publicLivechatGlobal.options.button_background_color; }, /** * @returns {string} */ _computeButtonText() { - if (this.messaging.publicLivechatOptions.button_text) { - return this.messaging.publicLivechatOptions.button_text; + if (this.messaging.publicLivechatGlobal.options.button_text) { + return this.messaging.publicLivechatGlobal.options.button_text; } return this.env._t("Chat with one of our collaborators"); }, @@ -28,14 +28,14 @@ registerModel({ * @returns {string} */ _computeButtonTextColor() { - return this.messaging.publicLivechatOptions.button_text_color; + return this.messaging.publicLivechatGlobal.options.button_text_color; }, /** * @private * @returns {integer} */ _computeChannelId() { - return this.messaging.publicLivechatOptions.channel_id; + return this.messaging.publicLivechatGlobal.options.channel_id; }, /** * @private @@ -84,18 +84,18 @@ registerModel({ * @returns {integer} */ _computeCurrentPartnerId() { - if (!this.messaging.isPublicLivechatAvailable) { + if (!this.messaging.publicLivechatGlobal.isAvailable) { return clear(); } - return this.messaging.publicLivechatOptions.current_partner_id; + return this.messaging.publicLivechatGlobal.options.current_partner_id; }, /** * @private * @returns {string} */ _computeDefaultMessage() { - if (this.messaging.publicLivechatOptions.default_message) { - return this.messaging.publicLivechatOptions.default_message; + if (this.messaging.publicLivechatGlobal.options.default_message) { + return this.messaging.publicLivechatGlobal.options.default_message; } return this.env._t("How may I help you?"); }, @@ -104,8 +104,8 @@ registerModel({ * @returns {string} */ _computeDefaultUsername() { - if (this.messaging.publicLivechatOptions.default_username) { - return this.messaging.publicLivechatOptions.default_username; + if (this.messaging.publicLivechatGlobal.options.default_username) { + return this.messaging.publicLivechatGlobal.options.default_username; } return this.env._t("Visitor"); }, @@ -114,7 +114,7 @@ registerModel({ * @returns {string} */ _computeHeaderBackgroundColor() { - return this.messaging.publicLivechatOptions.header_background_color; + return this.messaging.publicLivechatGlobal.options.header_background_color; }, /** * @private @@ -126,8 +126,8 @@ registerModel({ // as we use it for specific things (e.g: showing "please select an option above") return clear(); } - if (this.messaging.publicLivechatOptions.input_placeholder) { - return this.messaging.publicLivechatOptions.input_placeholder; + if (this.messaging.publicLivechatGlobal.options.input_placeholder) { + return this.messaging.publicLivechatGlobal.options.input_placeholder; } return this.env._t("Ask something ..."); }, @@ -161,7 +161,7 @@ registerModel({ if (!this.sessionCookie) { return clear(); } - const data = localStorage.getItem(this.sessionCookieKey); + const data = localStorage.getItem(this.chatbotSessionCookieKey); if (!data) { return clear(); } @@ -173,14 +173,14 @@ registerModel({ */ _computeServerUrl() { if (this.isChatbot) { - return this.messaging.publicLivechatServerUrlChatbot; + return this.messaging.publicLivechatGlobal.chatbotServerUrl; } - return this.messaging.publicLivechatServerUrl; + return this.messaging.publicLivechatGlobal.serverUrl; }, /** * @returns {string|FieldCommand} */ - _computeSessionCookieKey() { + _computeChatbotSessionCookieKey() { if (!this.sessionCookie) { return clear(); } @@ -191,7 +191,7 @@ registerModel({ * @returns {string} */ _computeTitleColor() { - return this.messaging.publicLivechatOptions.title_color; + return this.messaging.publicLivechatGlobal.options.title_color; }, }, fields: { @@ -213,6 +213,9 @@ registerModel({ inverse: 'livechatButtonViewOwner', isCausal: true, }), + chatbotSessionCookieKey: attr({ + compute: '_computeChatbotSessionCookieKey', + }), chatbotState: attr({ compute: '_computeChatbotState', }), @@ -272,9 +275,6 @@ registerModel({ compute: '_computeServerUrl', }), sessionCookie: attr(), - sessionCookieKey: attr({ - compute: '_computeSessionCookieKey', - }), testChatbotData: attr(), titleColor: attr({ compute: '_computeTitleColor', diff --git a/addons/im_livechat/static/src/models/messaging.js b/addons/im_livechat/static/src/models/messaging.js index 3895166f897..8d845ab7ae1 100644 --- a/addons/im_livechat/static/src/models/messaging.js +++ b/addons/im_livechat/static/src/models/messaging.js @@ -1,18 +1,12 @@ /** @odoo-module **/ import { addFields, addRecordMethods, patchRecordMethods } from '@mail/model/model_core'; -import { attr, many, one } from '@mail/model/model_field'; +import { many, one } from '@mail/model/model_field'; import { clear, insertAndReplace } from '@mail/model/model_field_command'; // ensure that the model definition is loaded before the patch import '@mail/models/messaging'; addFields('Messaging', { - isInPublicLivechat: attr({ - default: false, - }), - isPublicLivechatAvailable: attr({ - default: false, - }), livechatButtonView: one('LivechatButtonView', { compute: '_computeLivechatButtonView', isCausal: true, @@ -24,11 +18,8 @@ addFields('Messaging', { inverse: 'messagingAsPinnedLivechat', readonly: true, }), - publicLivechatOptions: attr({ - default: {}, - }), - publicLivechatServerUrl: attr({ - default: '', + publicLivechatGlobal: one('PublicLivechatGlobal', { + isCausal: true, }), }); @@ -38,7 +29,7 @@ addRecordMethods('Messaging', { * @returns {FieldCommand} */ _computeLivechatButtonView() { - if (this.isInPublicLivechat && this.isPublicLivechatAvailable) { + if (this.publicLivechatGlobal && this.publicLivechatGlobal.isAvailable) { return insertAndReplace(); } return clear(); @@ -50,7 +41,7 @@ patchRecordMethods('Messaging', { * @override */ _computeNotificationHandler() { - if (this.isInPublicLivechat) { + if (this.publicLivechatGlobal) { return clear(); } return this._super(); diff --git a/addons/im_livechat/static/src/models/messaging_initializer.js b/addons/im_livechat/static/src/models/messaging_initializer.js index 9b1e1b231e2..19a19ccd503 100644 --- a/addons/im_livechat/static/src/models/messaging_initializer.js +++ b/addons/im_livechat/static/src/models/messaging_initializer.js @@ -10,7 +10,7 @@ patchRecordMethods('MessagingInitializer', { * @override */ async performInitRpc() { - if (this.messaging.isInPublicLivechat) { + if (this.messaging.publicLivechatGlobal) { return {}; } else { return this._super(); diff --git a/addons/im_livechat/static/src/models/public_livechat.js b/addons/im_livechat/static/src/models/public_livechat.js index 8af2b0c9683..c9e49744b04 100644 --- a/addons/im_livechat/static/src/models/public_livechat.js +++ b/addons/im_livechat/static/src/models/public_livechat.js @@ -3,36 +3,38 @@ import PublicLivechat from '@im_livechat/legacy/models/public_livechat'; import { registerModel } from '@mail/model/model_core'; -import { attr, one } from '@mail/model/model_field'; -import { clear } from '@mail/model/model_field_command'; +import { attr, many, one } from '@mail/model/model_field'; registerModel({ name: 'PublicLivechat', identifyingFields: ['livechatButtonOwner'], - recordMethods: { - /** - * @private - * @returns {FieldCommand|im_livechat/legacy/models/public_livechat} - */ - _computeLegacyPublicLivechat() { - if (!this.data) { - return clear(); - } - return new PublicLivechat({ - parent: this.livechatButtonOwner.widget, - data: this.data, + lifecycleHooks: { + _created() { + this.update({ + legacyPublicLivechat: new PublicLivechat(this.messaging, { + parent: this.livechatButtonOwner.widget, + data: this.data, + }), }); }, + _willDelete() { + this.legacyPublicLivechat.destroy(); + }, + }, + recordMethods: { }, fields: { data: attr(), - legacyPublicLivechat: attr({ - compute: '_computeLegacyPublicLivechat', - }), + legacyPublicLivechat: attr(), livechatButtonOwner: one('LivechatButtonView', { inverse: 'publicLivechat', readonly: true, required: true, }), + messages: many('PublicLivechatMessage'), + // amount of messages that have not yet been read on this chat + unreadCounter: attr({ + default: 0, + }), }, }); diff --git a/addons/im_livechat/static/src/models/public_livechat_global.js b/addons/im_livechat/static/src/models/public_livechat_global.js new file mode 100644 index 00000000000..ba551eae407 --- /dev/null +++ b/addons/im_livechat/static/src/models/public_livechat_global.js @@ -0,0 +1,21 @@ +/** @odoo-module **/ + +import { registerModel } from '@mail/model/model_core'; +import { attr } from '@mail/model/model_field'; + +registerModel({ + name: 'PublicLivechatGlobal', + identifyingFields: ['messaging'], + fields: { + chatbotServerUrl: attr(), + isAvailable: attr({ + default: false, + }), + options: attr({ + default: {}, + }), + serverUrl: attr({ + default: '', + }), + }, +}); diff --git a/addons/im_livechat/static/src/models/public_livechat_message.js b/addons/im_livechat/static/src/models/public_livechat_message.js new file mode 100644 index 00000000000..e0853e88b87 --- /dev/null +++ b/addons/im_livechat/static/src/models/public_livechat_message.js @@ -0,0 +1,16 @@ +/** @odoo-module **/ + +import { registerModel } from '@mail/model/model_core'; +import { attr } from '@mail/model/model_field'; + +registerModel({ + name: 'PublicLivechatMessage', + identifyingFields: ['id'], + fields: { + id: attr({ + readonly: true, + required: true, + }), + legacyPublicLivechatMessage: attr(), + }, +}); diff --git a/addons/im_livechat/static/src/models/public_livechat_window.js b/addons/im_livechat/static/src/models/public_livechat_window.js index a6ad3972f11..cc69ef41179 100644 --- a/addons/im_livechat/static/src/models/public_livechat_window.js +++ b/addons/im_livechat/static/src/models/public_livechat_window.js @@ -4,43 +4,31 @@ import PublicLivechatWindow from '@im_livechat/legacy/widgets/public_livechat_wi 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: 'PublicLivechatWindow', identifyingFields: ['livechatButtonViewOwner'], lifecycleHooks: { - _willDelete() { - if (this.legacyChatWindow) { - this.legacyChatWindow.destroy(); - } + _created() { + this.update({ + legacyChatWindow: new PublicLivechatWindow( + this.livechatButtonViewOwner.widget, + this.messaging, + this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat, + { + headerBackgroundColor: this.livechatButtonViewOwner.headerBackgroundColor, + placeholder: this.livechatButtonViewOwner.inputPlaceholder, + titleColor: this.livechatButtonViewOwner.titleColor, + }, + ), + }); }, - }, - recordMethods: { - /** - * @private - * @returns {im_livechat/legacy/widgets/public_chat_window|FieldCommand} - */ - _computeLegacyChatWindow() { - if (!this.livechatButtonViewOwner.widget && this.legacyChatWindow) { - this.legacyChatWindow.destroy(); - return clear(); - } - return new PublicLivechatWindow( - this.livechatButtonViewOwner.widget, - this.messaging.livechatButtonView.publicLivechat.legacyPublicLivechat, - { - displayStars: false, - headerBackgroundColor: this.livechatButtonViewOwner.headerBackgroundColor, - placeholder: this.livechatButtonViewOwner.inputPlaceholder, - titleColor: this.livechatButtonViewOwner.titleColor, - }, - ); + _willDelete() { + this.legacyChatWindow.destroy(); }, }, fields: { legacyChatWindow: attr({ - compute: '_computeLegacyChatWindow', default: null, }), livechatButtonViewOwner: one('LivechatButtonView', { diff --git a/addons/im_livechat/static/src/public/main.js b/addons/im_livechat/static/src/public/main.js index 159711679f4..2e7f9f371a0 100644 --- a/addons/im_livechat/static/src/public/main.js +++ b/addons/im_livechat/static/src/public/main.js @@ -3,6 +3,7 @@ import { publicLivechatService } from '@im_livechat/services/public_livechat_service'; import { isAvailable, options, serverUrl } from 'im_livechat.loaderData'; +import { insertAndReplace } from '@mail/model/model_field_command'; import { messagingService } from '@mail/services/messaging_service'; import { makeMessagingToLegacyEnv } from '@mail/utils/make_messaging_to_legacy_env'; @@ -11,10 +12,7 @@ import { registry } from '@web/core/registry'; const messagingValuesService = { start() { return { - isInPublicLivechat: true, - isPublicLivechatAvailable: isAvailable, - publicLivechatOptions: options, - publicLivechatServerUrl: serverUrl, + publicLivechatGlobal: insertAndReplace({ isAvailable, options, serverUrl }), }; } }; diff --git a/addons/website_livechat/static/src/legacy/website_livechat_chatbot_test_script.js b/addons/website_livechat/static/src/legacy/website_livechat_chatbot_test_script.js index 1894a48f9c6..2aed88feef3 100644 --- a/addons/website_livechat/static/src/legacy/website_livechat_chatbot_test_script.js +++ b/addons/website_livechat/static/src/legacy/website_livechat_chatbot_test_script.js @@ -90,9 +90,7 @@ publicWidget.registry.livechatChatbotTestScript = publicWidget.Widget.extend({ const messaging = this.env.services.messaging.get(); return this._super(...arguments).then(() => { messaging.update({ - isInPublicLivechat: true, - isPublicLivechatAvailable: true, - publicLivechatServerUrlChatbot: this.$el.data().serverUrl, + publicLivechatGlobal: insertAndReplace({ isAvailable: true, chatbotServerUrl: this.$el.data().serverUrl }), }); this.livechatButton = new LivechatButtonTestChatbot(this, messaging, this.$el.data()); this.livechatButton.appendTo(document.body); diff --git a/addons/website_livechat/static/src/models/messaging.js b/addons/website_livechat/static/src/models/messaging.js deleted file mode 100644 index 92f4db61ebf..00000000000 --- a/addons/website_livechat/static/src/models/messaging.js +++ /dev/null @@ -1,10 +0,0 @@ -/** @odoo-module **/ - -import { addFields } from '@mail/model/model_core'; -import { attr } from '@mail/model/model_field'; -// ensure that the model definition is loaded before the patch -import '@mail/models/messaging'; - -addFields('Messaging', { - publicLivechatServerUrlChatbot: attr(), -});