diff --git a/addons/im_livechat/static/src/components/thread_needaction_preview/thread_needaction_preview.js b/addons/im_livechat/static/src/components/thread_needaction_preview/thread_needaction_preview.js index 67e58fe1d1f..26199e15240 100644 --- a/addons/im_livechat/static/src/components/thread_needaction_preview/thread_needaction_preview.js +++ b/addons/im_livechat/static/src/components/thread_needaction_preview/thread_needaction_preview.js @@ -1,13 +1,12 @@ /** @odoo-module **/ -import { ThreadNeedactionPreviewView } from '@mail/components/thread_needaction_preview/thread_needaction_preview'; +import { ThreadNeedactionPreviewView } from "@mail/components/thread_needaction_preview/thread_needaction_preview"; -import { patch } from 'web.utils'; +import { patch } from "web.utils"; const components = { ThreadNeedactionPreviewView }; -patch(components.ThreadNeedactionPreviewView.prototype, 'thread_needaction_preview', { - +patch(components.ThreadNeedactionPreviewView.prototype, "thread_needaction_preview", { //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- @@ -16,10 +15,12 @@ patch(components.ThreadNeedactionPreviewView.prototype, 'thread_needaction_previ * @override */ image(...args) { - if (this.threadNeedactionPreviewView.thread.channel && this.threadNeedactionPreviewView.thread.channel.channel_type === 'livechat') { - return '/mail/static/src/img/smiley/avatar.jpg'; + if ( + this.threadNeedactionPreviewView.thread.channel && + this.threadNeedactionPreviewView.thread.channel.channel_type === "livechat" + ) { + return "/mail/static/src/img/smiley/avatar.jpg"; } return this._super(...args); - } - + }, }); diff --git a/addons/im_livechat/static/src/js/ajax_external.js b/addons/im_livechat/static/src/js/ajax_external.js index 1ef672b8ec2..892423458e7 100644 --- a/addons/im_livechat/static/src/js/ajax_external.js +++ b/addons/im_livechat/static/src/js/ajax_external.js @@ -3,10 +3,10 @@ import { assets } from "@web/core/assets"; /** - * This file should be used in the context of an external widget loading (e.g: live chat in a non-Odoo website) - * It overrides the 'loadJS' method that is supposed to load additional scripts, based on a relative URL (e.g: '/web/webclient/locale/en_US') - * As we're not in an Odoo website context, the calls will not work, and we avoid a 404 request. - */ + * This file should be used in the context of an external widget loading (e.g: live chat in a non-Odoo website) + * It overrides the 'loadJS' method that is supposed to load additional scripts, based on a relative URL (e.g: '/web/webclient/locale/en_US') + * As we're not in an Odoo website context, the calls will not work, and we avoid a 404 request. + */ assets.loadJS = function (url) { - console.log('Tried to load the following script on an external website: ' + url); + console.log("Tried to load the following script on an external website: " + url); }; diff --git a/addons/im_livechat/static/src/js/colors_reset_button/colors_reset_button.js b/addons/im_livechat/static/src/js/colors_reset_button/colors_reset_button.js index 05921151955..e1114f10d49 100644 --- a/addons/im_livechat/static/src/js/colors_reset_button/colors_reset_button.js +++ b/addons/im_livechat/static/src/js/colors_reset_button/colors_reset_button.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { registry } from '@web/core/registry'; +import { registry } from "@web/core/registry"; import { standardWidgetProps } from "@web/views/widgets/standard_widget_props"; const { Component } = owl; @@ -20,4 +20,4 @@ ColorsResetButton.extractProps = ({ attrs }) => { return attrs.options; }; -registry.category('view_widgets').add('colors_reset_button', ColorsResetButton); +registry.category("view_widgets").add("colors_reset_button", ColorsResetButton); diff --git a/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js b/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js index 9a37c0b3543..5c8c0873b92 100644 --- a/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js +++ b/addons/im_livechat/static/src/js/im_livechat_chatbot_script_answers_m2m.js @@ -1,6 +1,5 @@ /** @odoo-module **/ - import { registry } from "@web/core/registry"; import { Many2ManyTagsField, @@ -19,11 +18,11 @@ export class ChatbotScriptTriggeringAnswersMany2Many extends Many2ManyTagsField if (this.props.record.model.root.data.id) { this.env.services.user.updateContext({ - force_domain_chatbot_script_id: this.props.record.model.root.data.id + force_domain_chatbot_script_id: this.props.record.model.root.data.id, }); } } -}; +} export const chatbotScriptTriggeringAnswersMany2Many = { ...many2ManyTagsField, diff --git a/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js b/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js index 20c57e3a791..1c87efd1e8b 100644 --- a/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js +++ b/addons/im_livechat/static/src/js/im_livechat_chatbot_steps_one2many.js @@ -2,24 +2,28 @@ import { ListRenderer } from "@web/views/list/list_renderer"; import { registry } from "@web/core/registry"; -import { patch } from '@web/core/utils/patch'; -import { useX2ManyCrud, useOpenX2ManyRecord, X2ManyFieldDialog } from "@web/views/fields/relational_utils"; +import { patch } from "@web/core/utils/patch"; +import { + useX2ManyCrud, + useOpenX2ManyRecord, + X2ManyFieldDialog, +} from "@web/views/fields/relational_utils"; import { X2ManyField, x2ManyField } from "@web/views/fields/x2many/x2many_field"; const fieldRegistry = registry.category("fields"); -patch(X2ManyFieldDialog.prototype, 'chatbot_script_step_sequence', { +patch(X2ManyFieldDialog.prototype, "chatbot_script_step_sequence", { /** * Dirty patching of the 'X2ManyFieldDialog'. * It is done to force the "save and new" to close the dialog first, and then click again on * the "Add a line" link. - * + * * This is the only way (or at least the least complicated) to correctly compute the sequence * field, which is crucial when creating chatbot.steps, as they depend on each other. - * + * */ async save({ saveAndNew }) { - if (this.record.resModel !== 'chatbot.script.step') { + if (this.record.resModel !== "chatbot.script.step") { return this._super(...arguments); } @@ -30,12 +34,12 @@ patch(X2ManyFieldDialog.prototype, 'chatbot_script_step_sequence', { } if (saveAndNew) { - document.querySelector('.o_field_x2many_list_row_add a').click(); + document.querySelector(".o_field_x2many_list_row_add a").click(); } this.props.close(); return true; - } + }, }); export class ChatbotStepsOne2manyRenderer extends ListRenderer { @@ -65,10 +69,7 @@ export class ChatbotStepsOne2many extends X2ManyField { setup() { super.setup(); - const { saveRecord, updateRecord } = useX2ManyCrud( - () => this.list, - this.isMany2Many - ); + const { saveRecord, updateRecord } = useX2ManyCrud(() => this.list, this.isMany2Many); const openRecord = useOpenX2ManyRecord({ resModel: this.list.resModel, @@ -77,7 +78,7 @@ export class ChatbotStepsOne2many extends X2ManyField { getList: () => this.list, saveRecord: async (record) => { await saveRecord(record); - await this.props.record.save({stayInEdition: true}); + await this.props.record.save({ stayInEdition: true }); }, updateRecord: updateRecord, }); @@ -94,7 +95,7 @@ export class ChatbotStepsOne2many extends X2ManyField { }); }; } -}; +} export const chatbotStepsOne2many = { ...x2ManyField, @@ -105,5 +106,5 @@ fieldRegistry.add("chatbot_steps_one2many", chatbotStepsOne2many); ChatbotStepsOne2many.components = { ...X2ManyField.components, - ListRenderer: ChatbotStepsOne2manyRenderer + ListRenderer: ChatbotStepsOne2manyRenderer, }; diff --git a/addons/im_livechat/static/src/legacy/models/cc_throttle_function.js b/addons/im_livechat/static/src/legacy/models/cc_throttle_function.js index 463fc3331a7..17b739dd8ba 100644 --- a/addons/im_livechat/static/src/legacy/models/cc_throttle_function.js +++ b/addons/im_livechat/static/src/legacy/models/cc_throttle_function.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import CCThrottleFunctionObject from '@im_livechat/legacy/models/cc_throttle_function_object'; +import CCThrottleFunctionObject from "@im_livechat/legacy/models/cc_throttle_function_object"; /** * A function that creates a cancellable and clearable (CC) throttle version diff --git a/addons/im_livechat/static/src/legacy/models/cc_throttle_function_object.js b/addons/im_livechat/static/src/legacy/models/cc_throttle_function_object.js index d180b466325..605151827b0 100644 --- a/addons/im_livechat/static/src/legacy/models/cc_throttle_function_object.js +++ b/addons/im_livechat/static/src/legacy/models/cc_throttle_function_object.js @@ -1,13 +1,12 @@ /** @odoo-module **/ -import Class from 'web.Class'; +import Class from "web.Class"; /** * This object models the behaviour of the clearable and cancellable (CC) * throttle version of a provided function. */ const CCThrottleFunctionObject = Class.extend({ - /** * @param {Object} params * @param {integer} params.duration duration of the 'cooldown' phase, i.e. @@ -90,10 +89,7 @@ const CCThrottleFunctionObject = Class.extend({ */ _cooldown() { this.cancel(); - this._cooldownTimeout = setTimeout( - this._onCooldownTimeout.bind(this), - this._duration - ); + this._cooldownTimeout = setTimeout(this._onCooldownTimeout.bind(this), this._duration); }, //-------------------------------------------------------------------------- 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 aaeb6abc95b..5dbb608017a 100644 --- a/addons/im_livechat/static/src/legacy/models/public_livechat.js +++ b/addons/im_livechat/static/src/legacy/models/public_livechat.js @@ -1,14 +1,14 @@ /** @odoo-module **/ -import CCThrottleFunction from '@im_livechat/legacy/models/cc_throttle_function'; -import Timer from '@im_livechat/legacy/models/timer'; -import Timers from '@im_livechat/legacy/models/timers'; +import CCThrottleFunction from "@im_livechat/legacy/models/cc_throttle_function"; +import Timer from "@im_livechat/legacy/models/timer"; +import Timers from "@im_livechat/legacy/models/timers"; -import Class from 'web.Class'; -import { _t } from 'web.core'; -import session from 'web.session'; -import Mixins from 'web.mixins'; -import { sprintf } from 'web.utils'; +import Class from "web.Class"; +import { _t } from "web.core"; +import session from "web.session"; +import Mixins from "web.mixins"; +import { sprintf } from "web.utils"; /** * Thread model that represents a livechat on the website-side. This livechat @@ -98,14 +98,18 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { if (params.data.message_unread_counter !== undefined) { this.messaging.publicLivechatGlobal.publicLivechat.update({ - unreadCounter: params.data.message_unread_counter + unreadCounter: params.data.message_unread_counter, }); } if (_.isBoolean(params.data.folded)) { - this.messaging.publicLivechatGlobal.publicLivechat.update({ isFolded: params.data.folded }); + this.messaging.publicLivechatGlobal.publicLivechat.update({ + isFolded: params.data.folded, + }); } else { - this.messaging.publicLivechatGlobal.publicLivechat.update({ isFolded: params.data.state === 'folded' }); + this.messaging.publicLivechatGlobal.publicLivechat.update({ + isFolded: params.data.state === "folded", + }); } }, @@ -136,9 +140,11 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { * @override * @returns {@im_livechat/legacy/models/public_livechat_message[]} */ - getMessages() { + getMessages() { // ignore removed messages - return this.messaging.publicLivechatGlobal.messages.filter(message => !message.widget.isEmpty()).map(message => message.widget); + return this.messaging.publicLivechatGlobal.messages + .filter((message) => !message.widget.isEmpty()) + .map((message) => message.widget); }, /** * Get the text to display when some partners are typing something on the @@ -167,28 +173,34 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { */ getTypingMembersToText() { const typingPartnerIDs = this._typingPartnerIDs; - const typingMembers = ( - this.messaging.publicLivechatGlobal.publicLivechat.operator && this._typingPartnerIDs.includes(this.messaging.publicLivechatGlobal.publicLivechat.operator.id) - ? [this.messaging.publicLivechatGlobal.publicLivechat.operator] - : [] - ); + const typingMembers = + this.messaging.publicLivechatGlobal.publicLivechat.operator && + this._typingPartnerIDs.includes( + this.messaging.publicLivechatGlobal.publicLivechat.operator.id + ) + ? [this.messaging.publicLivechatGlobal.publicLivechat.operator] + : []; const sortedTypingMembers = _.sortBy(typingMembers, function (member) { return _.indexOf(typingPartnerIDs, member.id); }); const displayableTypingMembers = sortedTypingMembers.slice(0, 3); if (displayableTypingMembers.length === 0) { - return ''; + return ""; } else if (displayableTypingMembers.length === 1) { return sprintf(_t("%s is typing..."), displayableTypingMembers[0].name); } else if (displayableTypingMembers.length === 2) { - return sprintf(_t("%s and %s are typing..."), - displayableTypingMembers[0].name, - displayableTypingMembers[1].name); + return sprintf( + _t("%s and %s are typing..."), + displayableTypingMembers[0].name, + displayableTypingMembers[1].name + ); } else { - return sprintf(_t("%s, %s and more are typing..."), - displayableTypingMembers[0].name, - displayableTypingMembers[1].name); + return sprintf( + _t("%s, %s and more are typing..."), + displayableTypingMembers[0].name, + displayableTypingMembers[1].name + ); } }, /** @@ -204,7 +216,7 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { * @returns {boolean} */ isSomeoneTyping() { - return !(_.isEmpty(this._typingPartnerIDs)); + return !_.isEmpty(this._typingPartnerIDs); }, /** * Mark the thread as read, which resets the unread counter to 0. This is @@ -289,18 +301,18 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { */ toData() { return { - chatbot_script_id: this.messaging.publicLivechatGlobal.publicLivechat.data.chatbot_script_id, + chatbot_script_id: + this.messaging.publicLivechatGlobal.publicLivechat.data.chatbot_script_id, folded: this.messaging.publicLivechatGlobal.publicLivechat.isFolded, id: this.messaging.publicLivechatGlobal.publicLivechat.id, - message_unread_counter: this.messaging.publicLivechatGlobal.publicLivechat.unreadCounter, - operator_pid: ( - this.messaging.publicLivechatGlobal.publicLivechat.operator + message_unread_counter: + this.messaging.publicLivechatGlobal.publicLivechat.unreadCounter, + operator_pid: this.messaging.publicLivechatGlobal.publicLivechat.operator ? [ - this.messaging.publicLivechatGlobal.publicLivechat.operator.id, - this.messaging.publicLivechatGlobal.publicLivechat.operator.name, - ] - : [] - ), + this.messaging.publicLivechatGlobal.publicLivechat.operator.id, + this.messaging.publicLivechatGlobal.publicLivechat.operator.name, + ] + : [], name: this.messaging.publicLivechatGlobal.publicLivechat.name, uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, }; @@ -344,10 +356,14 @@ const PublicLivechat = Class.extend(Mixins.EventDispatcherMixin, { // sent. Until then, do not notify visitor is typing. return; } - return session.rpc('/im_livechat/notify_typing', { - uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, - is_typing: params.typing, - }, { shadow: true }); + return session.rpc( + "/im_livechat/notify_typing", + { + uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, + is_typing: params.typing, + }, + { shadow: true } + ); }, /** * Warn views that the list of users that are currently typing on this 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 942a3f3641a..0815d470113 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 @@ -1,11 +1,11 @@ /** @odoo-module **/ -import * as mailUtils from '@mail/js/utils'; +import * as mailUtils from "@mail/js/utils"; -import Class from 'web.Class'; -import { _t } from 'web.core'; -import session from 'web.session'; -import time from 'web.time'; +import Class from "web.Class"; +import { _t } from "web.core"; +import session from "web.session"; +import time from "web.time"; /** * This is a message that is handled by im_livechat, without making use of the @@ -15,7 +15,6 @@ import time from 'web.time'; * @see @im_livechat/legacy/models/public_livechat_message for more information. */ const PublicLivechatMessage = Class.extend({ - /** * @param {@im_livechat/legacy/widgets/livechat_button} parent * @param {Messaging} messaging @@ -78,7 +77,7 @@ const PublicLivechatMessage = Class.extend({ } else if (this.hasAuthor() && session.user_id) { source += `/web/image/res.partner/${this.getAuthorID()}/avatar_128`; } else { - source += '/mail/static/src/img/smiley/avatar.jpg'; + source += "/mail/static/src/img/smiley/avatar.jpg"; } return source; }, @@ -120,13 +119,13 @@ const PublicLivechatMessage = Class.extend({ * @return {string} */ getDateDay() { - const date = this.getDate().format('YYYY-MM-DD'); - if (date === moment().format('YYYY-MM-DD')) { + const date = this.getDate().format("YYYY-MM-DD"); + if (date === moment().format("YYYY-MM-DD")) { return _t("Today"); - } else if (date === moment().subtract(1, 'days').format('YYYY-MM-DD')) { + } else if (date === moment().subtract(1, "days").format("YYYY-MM-DD")) { return _t("Yesterday"); } - return this.getDate().format('LL'); + return this.getDate().format("LL"); }, /** * Get the text to display for the author of the message @@ -260,9 +259,11 @@ const PublicLivechatMessage = Class.extend({ * @return {boolean} */ _isMyselfAuthor() { - return this.hasAuthor() && (this.getAuthorID() === this.messaging.publicLivechatGlobal.options.current_partner_id); + return ( + this.hasAuthor() && + this.getAuthorID() === this.messaging.publicLivechatGlobal.options.current_partner_id + ); }, - }); export default PublicLivechatMessage; diff --git a/addons/im_livechat/static/src/legacy/models/timer.js b/addons/im_livechat/static/src/legacy/models/timer.js index 3e6b647930a..066c05a47c7 100644 --- a/addons/im_livechat/static/src/legacy/models/timer.js +++ b/addons/im_livechat/static/src/legacy/models/timer.js @@ -1,12 +1,11 @@ /** @odoo-module **/ -import Class from 'web.Class'; +import Class from "web.Class"; /** * This class creates a timer which, when times out, calls a function. */ const Timer = Class.extend({ - /** * Instantiate a new timer. Note that the timer is not started on * initialization (@see start method). @@ -60,7 +59,6 @@ const Timer = Class.extend({ _onTimeout() { this._timeoutCallback(); }, - }); export default Timer; diff --git a/addons/im_livechat/static/src/legacy/models/timers.js b/addons/im_livechat/static/src/legacy/models/timers.js index 085055b903b..7c83bba00fe 100644 --- a/addons/im_livechat/static/src/legacy/models/timers.js +++ b/addons/im_livechat/static/src/legacy/models/timers.js @@ -1,14 +1,13 @@ /** @odoo-module **/ -import Timer from '@im_livechat/legacy/models/timer'; +import Timer from "@im_livechat/legacy/models/timer"; -import Class from 'web.Class'; +import Class from "web.Class"; /** * This class lists several timers that use a same callback and duration. */ const Timers = Class.extend({ - /** * Instantiate a new list of timers * @@ -39,7 +38,7 @@ const Timers = Class.extend({ * @param {Array} [params.timeoutCallbackArguments] * @param {integer} params.timerID */ - registerTimer(params) { + registerTimer(params) { const timerID = params.timerID; if (this._timers[timerID]) { this._timers[timerID].clear(); @@ -48,11 +47,11 @@ const Timers = Class.extend({ duration: this._duration, onTimeout: this._timeoutCallback, }; - if ('timeoutCallbackArguments' in params) { - timerParams.onTimeout = this._timeoutCallback.bind.apply( - this._timeoutCallback, - [null, ...params.timeoutCallbackArguments] - ); + if ("timeoutCallbackArguments" in params) { + timerParams.onTimeout = this._timeoutCallback.bind.apply(this._timeoutCallback, [ + null, + ...params.timeoutCallbackArguments, + ]); } else { timerParams.onTimeout = this._timeoutCallback; } @@ -66,14 +65,13 @@ const Timers = Class.extend({ * @param {Object} params * @param {integer} params.timerID */ - unregisterTimer(params) { + unregisterTimer(params) { const timerID = params.timerID; if (this._timers[timerID]) { this._timers[timerID].clear(); delete this._timers[timerID]; } }, - }); export default Timers; diff --git a/addons/im_livechat/static/src/legacy/public_livechat.scss b/addons/im_livechat/static/src/legacy/public_livechat.scss index d936804f5e1..76d151b2307 100644 --- a/addons/im_livechat/static/src/legacy/public_livechat.scss +++ b/addons/im_livechat/static/src/legacy/public_livechat.scss @@ -21,7 +21,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; @include media-breakpoint-down(md) { width: 100%; - height: 100%!important; + height: 100% !important; box-shadow: none; &.o_folded { display: none; @@ -37,9 +37,9 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; display: flex; flex: 0 0 auto; color: white; - padding: $o-mail-chatter-gap*0.5 $o-mail-chatter-gap; + padding: $o-mail-chatter-gap * 0.5 $o-mail-chatter-gap; border-radius: 3px 3px 0 0; - border-bottom: 1px solid map-get($grays, '300'); + border-bottom: 1px solid map-get($grays, "300"); background-color: $o-brand-odoo; padding: 8px; cursor: pointer; @@ -89,7 +89,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; padding-left: 2px; .o_mail_thread_typing_icon_dot { - background: map-get($grays, '300'); + background: map-get($grays, "300"); } } } @@ -103,7 +103,6 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; @include o-hover-opacity(0.7, 1); } } - } .o_mail_thread { @@ -139,7 +138,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; width: auto; height: 28px; color: white; - background-color: map-get($grays, '900'); + background-color: map-get($grays, "900"); cursor: pointer; box-shadow: none; @@ -172,7 +171,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; > li.o_thread_window_header { font-size: 12px; padding: 3px 5px; - &~li.o_thread_window_header { + & ~ li.o_thread_window_header { border-top: 1px solid white; } &:hover { @@ -197,7 +196,6 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; // legacy: mail/thread.scss //------------------------------------- - .o_mail_thread_loading { display: flex; align-items: center; @@ -208,7 +206,8 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; margin-right: 5px; } -.o_mail_thread, .o_mail_activity { +.o_mail_thread, +.o_mail_activity { .o_thread_show_more { text-align: center; } @@ -230,7 +229,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; margin-top: 0px; margin-bottom: 15px; } - border-bottom: 1px solid map-get($grays, '400'); + border-bottom: 1px solid map-get($grays, "400"); text-align: center; .o_thread_date { @@ -263,8 +262,8 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; margin-bottom: 0px; &.o_mail_not_discussion { - background-color: rgba(map-get($grays, '300'), 0.5); - border-bottom: 1px solid map-get($grays, '400'); + background-color: rgba(map-get($grays, "300"), 0.5); + border-bottom: 1px solid map-get($grays, "400"); } .o_thread_message_sidebar { @@ -323,7 +322,8 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; } } - &:hover, &.o_thread_selected_message { + &:hover, + &.o_thread_selected_message { .o_thread_message_side_date { display: inline-block; opacity: $o-mail-thread-side-date-opacity; @@ -365,7 +365,8 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; color: gray; } - [summary~=o_mail_notification] { // name conflicts with channel notifications, but is odoo notification buttons to hide in chatter if present + [summary~="o_mail_notification"] { + // name conflicts with channel notifications, but is odoo notification buttons to hide in chatter if present display: none; } @@ -396,7 +397,10 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; } } - .o_thread_message_star, .o_thread_message_needaction, .o_thread_message_reply, .o_thread_message_notification { + .o_thread_message_star, + .o_thread_message_needaction, + .o_thread_message_reply, + .o_thread_message_notification { padding: 4px; } @@ -409,7 +413,8 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; } } - .o_attachments_list, .o_attachments_previews { + .o_attachments_list, + .o_attachments_previews { &:last-child { margin-bottom: $grid-gutter-width; } @@ -443,7 +448,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; width: 3px; height: 3px; border-radius: 50%; - background: map-get($grays, '800'); + background: map-get($grays, "800"); animation: o_mail_thread_typing_icon_dot 1.5s linear infinite; &:nth-child(2) { @@ -457,7 +462,9 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; } @keyframes o_mail_thread_typing_icon_dot { - 0%, 40%, 100% { + 0%, + 40%, + 100% { transform: initial; } 20% { @@ -478,7 +485,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; cursor: pointer; white-space: nowrap; background-color: rgba(60, 60, 60, 0.6); - font-family: 'Lucida Grande', 'Lucida Sans Unicode', Arial, Verdana, sans-serif; + font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, Verdana, sans-serif; font-size: 14px; font-weight: bold; padding: 10px; @@ -498,7 +505,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; } .btn { - color: #FFFFFF; + color: #ffffff; background-color: #30908e; border-color: #2d8685; border: 1px solid transparent; @@ -532,9 +539,9 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; font-weight: 400; line-height: 1.5; color: #495057; - background-color: #FFFFFF; + background-color: #ffffff; background-clip: padding-box; - border: 1px solid #CED4DA; + border: 1px solid #ced4da; } button { display: inline-block; @@ -564,10 +571,11 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; > img { width: 65px; - opacity: 0.60; + opacity: 0.6; cursor: pointer; margin: 10px; - &:hover, &.selected { + &:hover, + &.selected { opacity: 1; } } @@ -606,7 +614,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; .o_PublicLivechatMessage { display: flex; position: relative; - + &.o-isVisitorTheAuthor { flex-direction: row-reverse !important; } @@ -648,7 +656,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; justify-content: flex-end; margin-left: map-get($spacers, 4); } - + &.o-isOperatorTheAuthor { margin-right: map-get($spacers, 4); } @@ -664,11 +672,10 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; &.o-isVisitorTheAuthor { margin-left: map-get($spacers, 2); } - + &.o-isOperatorTheAuthor { margin-right: map-get($spacers, 2); } - } .o_PublicLivechatMessage_background { @@ -678,11 +685,11 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; top: 0; width: 100%; height: 100%; - transition: opacity .5s ease-out; + transition: opacity 0.5s ease-out; margin-right: map-get($spacers, 5); border-bottom-right-radius: 0.6rem !important; border-bottom-left-radius: 0.6rem !important; - border: 1px solid #C9CCD2 !important; + border: 1px solid #c9ccd2 !important; &.o-isVisitorTheAuthor { border-bottom-left-radius: 0.6rem !important; @@ -700,7 +707,7 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default; border-color: #17a2b8 !important; background-color: rgba(23, 162, 184, 0.5) !important; color: #000; - opacity: 15% + opacity: 15%; } } 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 bc0e9df8477..759fef0f327 100644 --- a/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js +++ b/addons/im_livechat/static/src/legacy/public_livechat_chatbot.js @@ -1,10 +1,10 @@ /** @odoo-module **/ -import session from 'web.session'; -import time from 'web.time'; -import utils from 'web.utils'; +import session from "web.session"; +import time from "web.time"; +import utils from "web.utils"; -import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; +import LivechatButton from "@im_livechat/legacy/widgets/livechat_button"; /** * Override of the LivechatButton to include chatbot capabilities. @@ -14,11 +14,10 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; * - When the user picks an option or answers to the chatbot, display a "chatbot is typing..." * message for a couple seconds and then trigger the next step of the script */ - LivechatButton.include({ - - //-------------------------------------------------------------------------- - // Private - LiveChat Overrides - //-------------------------------------------------------------------------- +LivechatButton.include({ + //-------------------------------------------------------------------------- + // Private - LiveChat Overrides + //-------------------------------------------------------------------------- /** * @private @@ -28,7 +27,11 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; const parameters = this._super(...arguments); const { publicLivechat } = this.messaging.publicLivechatGlobal; - if (publicLivechat && publicLivechat.isTemporary && !publicLivechat.data.chatbot_script_id) { + if ( + publicLivechat && + publicLivechat.isTemporary && + !publicLivechat.data.chatbot_script_id + ) { return parameters; } else if (publicLivechat && publicLivechat.data.chatbot_script_id) { parameters.chatbot_script_id = publicLivechat.data.chatbot_script_id; @@ -46,7 +49,9 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; if (this.messaging.publicLivechatGlobal.chatbot.isActive) { this._sendWelcomeChatbotMessage( 0, - this.messaging.publicLivechatGlobal.chatbot.state === 'welcome' ? 0 : this.messaging.publicLivechatGlobal.chatbot.messageDelay, + this.messaging.publicLivechatGlobal.chatbot.state === "welcome" + ? 0 + : this.messaging.publicLivechatGlobal.chatbot.messageDelay ); } else { this._super(...arguments); @@ -79,16 +84,14 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; if (chatbotStep.chatbot_step_message) { this.messaging.publicLivechatGlobal.livechatButtonView.addMessage({ - id: '_welcome_' + stepIndex, + id: "_welcome_" + stepIndex, is_discussion: true, // important for css style -> we only want white background for chatbot - author: ( - this.messaging.publicLivechatGlobal.publicLivechat.operator + author: this.messaging.publicLivechatGlobal.publicLivechat.operator ? { - id: this.messaging.publicLivechatGlobal.publicLivechat.operator.id, - name: this.messaging.publicLivechatGlobal.publicLivechat.operator.name, - } - : [['clear']] - ), + id: this.messaging.publicLivechatGlobal.publicLivechat.operator.id, + name: this.messaging.publicLivechatGlobal.publicLivechat.operator.name, + } + : [["clear"]], body: utils.Markup(chatbotStep.chatbot_step_message), chatbot_script_step_id: chatbotStep.chatbot_script_step_id, chatbot_step_answers: chatbotStep.chatbot_step_answers, @@ -106,7 +109,10 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; this.messaging.publicLivechatGlobal.chatbot.update({ welcomeMessageTimeout: setTimeout(() => { - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { return; } this._sendWelcomeChatbotMessage(stepIndex + 1, welcomeMessageDelay); @@ -114,7 +120,10 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; }, welcomeMessageDelay), }); } else { - if (this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_step_type === 'forward_operator') { + if ( + this.messaging.publicLivechatGlobal.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 @@ -147,10 +156,10 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; ev.stopPropagation(); const $target = $(ev.currentTarget); - const stepId = $target.closest('ul').data('chatbotStepId'); - const selectedAnswer = $target.data('chatbotStepAnswerId'); + const stepId = $target.closest("ul").data("chatbotStepId"); + const selectedAnswer = $target.data("chatbotStepAnswerId"); - const redirectLink = $target.data('chatbotStepRedirectLink'); + const redirectLink = $target.data("chatbotStepRedirectLink"); this.messaging.publicLivechatGlobal.chatbot.update({ isRedirecting: !!redirectLink }); await this.messaging.publicLivechatGlobal.livechatButtonView.sendMessage({ @@ -171,18 +180,19 @@ import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; } const messageId = stepMessage.id; stepMessage.widget.setChatbotStepAnswerId(selectedAnswer); - this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_selected_answer_id = selectedAnswer; + this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_selected_answer_id = + selectedAnswer; this.messaging.publicLivechatGlobal.chatWindow.renderMessages(); this.messaging.publicLivechatGlobal.chatbot.saveSession(); - const saveAnswerPromise = session.rpc('/chatbot/answer/save', { + const saveAnswerPromise = session.rpc("/chatbot/answer/save", { channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, message_id: messageId, selected_answer_id: selectedAnswer, }); if (redirectLink) { - await saveAnswerPromise; // ensure answer is saved before redirecting + await saveAnswerPromise; // ensure answer is saved before redirecting window.location = redirectLink; } }, diff --git a/addons/im_livechat/static/src/legacy/widgets/feedback/feedback.js b/addons/im_livechat/static/src/legacy/widgets/feedback/feedback.js index 7bc8b8f88fc..afa149e3a9c 100644 --- a/addons/im_livechat/static/src/legacy/widgets/feedback/feedback.js +++ b/addons/im_livechat/static/src/legacy/widgets/feedback/feedback.js @@ -1,10 +1,10 @@ /** @odoo-module **/ -import concurrency from 'web.concurrency'; -import core from 'web.core'; -import session from 'web.session'; -import utils from 'web.utils'; -import Widget from 'web.Widget'; +import concurrency from "web.concurrency"; +import core from "web.core"; +import session from "web.session"; +import utils from "web.utils"; +import Widget from "web.Widget"; const _t = core._t; /* @@ -14,14 +14,14 @@ const _t = core._t; * (only for red smiley), and sends the user feedback to the server. */ const Feedback = Widget.extend({ - template: 'im_livechat.legacy.im_livechat.FeedBack', + template: "im_livechat.legacy.im_livechat.FeedBack", events: { - 'click .o_livechat_rating_choices img': '_onClickSmiley', - 'click .o_livechat_no_feedback span': '_onClickNoFeedback', - 'click .o_rating_submit_button': '_onClickSend', - 'click .o_email_chat_button': '_onEmailChat', - 'click .o_livechat_email_error .alert-link': '_onTryAgain', + "click .o_livechat_rating_choices img": "_onClickSmiley", + "click .o_livechat_no_feedback span": "_onClickNoFeedback", + "click .o_rating_submit_button": "_onClickSend", + "click .o_email_chat_button": "_onEmailChat", + "click .o_livechat_email_error .alert-link": "_onTryAgain", }, /** @@ -45,32 +45,35 @@ const Feedback = Widget.extend({ * @private * @param {Object} options */ - _sendFeedback(reason) { + _sendFeedback(reason) { const args = { uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, rate: this.rating, reason, }; - this.dp.add(session.rpc('/im_livechat/feedback', args)).then((response) => { + this.dp.add(session.rpc("/im_livechat/feedback", args)).then((response) => { const emoji = this.messaging.publicLivechatGlobal.RATING_TO_EMOJI[this.rating] || "??"; let content; if (!reason) { content = utils.sprintf(_t("Rating: %s"), emoji); - } - else { + } else { content = "Rating reason: \n" + reason; } - this.trigger('send_message', { content, isFeedback: true }); + this.trigger("send_message", { content, isFeedback: true }); }); }, /** - * @private - */ + * @private + */ _showThanksMessage() { - this.$('.o_livechat_rating_box').empty().append($('
', { - text: _t('Thank you for your feedback'), - class: 'text-muted' - })); + this.$(".o_livechat_rating_box") + .empty() + .append( + $("
", { + text: _t("Thank you for your feedback"), + class: "text-muted", + }) + ); }, //-------------------------------------------------------------------------- @@ -81,16 +84,16 @@ const Feedback = Widget.extend({ * @private */ _onClickNoFeedback() { - this.trigger('feedback_sent'); // will close the chat + this.trigger("feedback_sent"); // will close the chat }, /** * @private */ _onClickSend() { - this.$('.o_livechat_rating_reason').hide(); + this.$(".o_livechat_rating_reason").hide(); this._showThanksMessage(); if (_.isNumber(this.rating)) { - this._sendFeedback(this.$('textarea').val()); + this._sendFeedback(this.$("textarea").val()); } }, /** @@ -98,55 +101,59 @@ const Feedback = Widget.extend({ * @param {MouseEvent} ev */ _onClickSmiley(ev) { - this.rating = parseInt($(ev.currentTarget).data('value')); - this.$('.o_livechat_rating_choices img').removeClass('selected'); - this.$('.o_livechat_rating_choices img[data-value="' + this.rating + '"]').addClass('selected'); + this.rating = parseInt($(ev.currentTarget).data("value")); + this.$(".o_livechat_rating_choices img").removeClass("selected"); + this.$('.o_livechat_rating_choices img[data-value="' + this.rating + '"]').addClass( + "selected" + ); // only display textearea if bad smiley selected if (this.rating !== 5) { this._sendFeedback(); - this.$('.o_livechat_rating_reason').show(); + this.$(".o_livechat_rating_reason").show(); } else { - this.$('.o_livechat_rating_reason').hide(); + this.$(".o_livechat_rating_reason").hide(); this._showThanksMessage(); this._sendFeedback(); } }, /** - * @private - */ + * @private + */ _onEmailChat() { - const $email = this.$('#o_email'); + const $email = this.$("#o_email"); if (utils.is_email($email.val())) { - $email.removeAttr('title').removeClass('is-invalid').prop('disabled', true); - this.$('.o_email_chat_button').prop('disabled', true); + $email.removeAttr("title").removeClass("is-invalid").prop("disabled", true); + this.$(".o_email_chat_button").prop("disabled", true); this._rpc({ - route: '/im_livechat/email_livechat_transcript', + route: "/im_livechat/email_livechat_transcript", params: { uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, email: $email.val(), - } - }).then(() => { - this.$('o_livechat_email_sentLabel').show(); - this.$('o_livechat_email_receiveCopyLabel').hide(); - this.$('o_livechat_email_receiveCopyForm').hide(); - }).guardedCatch(() => { - this.$('.o_livechat_email').hide(); - this.$('.o_livechat_email_error').show(); - }); + }, + }) + .then(() => { + this.$("o_livechat_email_sentLabel").show(); + this.$("o_livechat_email_receiveCopyLabel").hide(); + this.$("o_livechat_email_receiveCopyForm").hide(); + }) + .guardedCatch(() => { + this.$(".o_livechat_email").hide(); + this.$(".o_livechat_email_error").show(); + }); } else { - $email.addClass('is-invalid').prop('title', _t('Invalid email address')); + $email.addClass("is-invalid").prop("title", _t("Invalid email address")); } }, /** - * @private - */ + * @private + */ _onTryAgain() { - this.$('#o_email').prop('disabled', false); - this.$('.o_email_chat_button').prop('disabled', false); - this.$('.o_livechat_email_error').hide(); - this.$('.o_livechat_email').show(); + this.$("#o_email").prop("disabled", false); + this.$(".o_email_chat_button").prop("disabled", false); + this.$(".o_livechat_email_error").hide(); + this.$(".o_livechat_email").show(); }, }); 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 002ce0ed1f9..e88e9bf5edc 100644 --- a/addons/im_livechat/static/src/legacy/widgets/livechat_button.js +++ b/addons/im_livechat/static/src/legacy/widgets/livechat_button.js @@ -1,13 +1,13 @@ /** @odoo-module **/ -import time from 'web.time'; -import {getCookie} from 'web.utils.cookies'; -import Widget from 'web.Widget'; +import time from "web.time"; +import { getCookie } from "web.utils.cookies"; +import Widget from "web.Widget"; const LivechatButton = Widget.extend({ - className: 'openerp o_livechat_button d-print-none', + className: "openerp o_livechat_button d-print-none", events: { - 'click': '_onClick' + click: "_onClick", }, init(parent, messaging) { this._super(parent); @@ -32,8 +32,8 @@ const LivechatButton = Widget.extend({ * @private * @return {integer} operator_id.partner_id.id if the cookie is set */ - _get_previous_operator_id() { - const cookie = getCookie('im_livechat_previous_operator_pid'); + _get_previous_operator_id() { + const cookie = getCookie("im_livechat_previous_operator_pid"); if (cookie) { return cookie; } @@ -55,17 +55,20 @@ const LivechatButton = Widget.extend({ */ _sendWelcomeMessage() { if (this.messaging.publicLivechatGlobal.livechatButtonView.defaultMessage) { - this.messaging.publicLivechatGlobal.livechatButtonView.addMessage({ - id: '_welcome', - author: { - id: this.messaging.publicLivechatGlobal.publicLivechat.operator.id, - name: this.messaging.publicLivechatGlobal.publicLivechat.operator.name, + this.messaging.publicLivechatGlobal.livechatButtonView.addMessage( + { + id: "_welcome", + author: { + id: this.messaging.publicLivechatGlobal.publicLivechat.operator.id, + name: this.messaging.publicLivechatGlobal.publicLivechat.operator.name, + }, + body: this.messaging.publicLivechatGlobal.livechatButtonView.defaultMessage, + date: time.datetime_to_str(new Date()), + model: "mail.channel", + res_id: this.messaging.publicLivechatGlobal.publicLivechat.id, }, - body: this.messaging.publicLivechatGlobal.livechatButtonView.defaultMessage, - date: time.datetime_to_str(new Date()), - model: "mail.channel", - res_id: this.messaging.publicLivechatGlobal.publicLivechat.id, - }, { prepend: true }); + { prepend: true } + ); } }, diff --git a/addons/im_livechat/static/src/legacy/widgets/public_livechat_view/public_livechat_view.js b/addons/im_livechat/static/src/legacy/widgets/public_livechat_view/public_livechat_view.js index 6df9b8a06a7..17b542431a5 100644 --- a/addons/im_livechat/static/src/legacy/widgets/public_livechat_view/public_livechat_view.js +++ b/addons/im_livechat/static/src/legacy/widgets/public_livechat_view/public_livechat_view.js @@ -1,10 +1,10 @@ /** @odoo-module **/ -import * as mailUtils from '@mail/js/utils'; +import * as mailUtils from "@mail/js/utils"; -import core from 'web.core'; -import time from 'web.time'; -import Widget from 'web.Widget'; +import core from "web.core"; +import time from "web.time"; +import Widget from "web.Widget"; const QWeb = core.qweb; const _lt = core._lt; @@ -23,20 +23,20 @@ const READ_LESS = _lt("read less"); * widget. */ const PublicLivechatView = Widget.extend({ - className: 'o_mail_thread', + className: "o_mail_thread", events: { - 'click a': '_onClickRedirect', - 'click img': '_onClickRedirect', - 'click strong': '_onClickRedirect', - 'click .o_thread_show_more': '_onClickShowMore', - 'click .o_thread_message_needaction': '_onClickMessageNeedaction', - 'click .o_thread_message_star': '_onClickMessageStar', - 'click .o_thread_message_reply': '_onClickMessageReply', - 'click .oe_mail_expand': '_onClickMailExpand', - 'click .o_thread_message': '_onClickMessage', - 'click': '_onClick', - 'click .o_thread_message_notification_error': '_onClickMessageNotificationError', + "click a": "_onClickRedirect", + "click img": "_onClickRedirect", + "click strong": "_onClickRedirect", + "click .o_thread_show_more": "_onClickShowMore", + "click .o_thread_message_needaction": "_onClickMessageNeedaction", + "click .o_thread_message_star": "_onClickMessageStar", + "click .o_thread_message_reply": "_onClickMessageReply", + "click .oe_mail_expand": "_onClickMailExpand", + "click .o_thread_message": "_onClickMessage", + click: "_onClick", + "click .o_thread_message_notification_error": "_onClickMessageNotificationError", }, /** @@ -85,13 +85,18 @@ const PublicLivechatView = Widget.extend({ */ render(options) { let shouldScrollToBottomAfterRendering = false; - if (this._currentThreadID === this.messaging.publicLivechatGlobal.publicLivechat.id && this.isAtBottom()) { + if ( + this._currentThreadID === this.messaging.publicLivechatGlobal.publicLivechat.id && + this.isAtBottom() + ) { shouldScrollToBottomAfterRendering = true; } this._currentThreadID = this.messaging.publicLivechatGlobal.publicLivechat.id; // copy so that reverse do not alter order in the thread object - const messages = _.clone(this.messaging.publicLivechatGlobal.publicLivechat.widget.getMessages()); + const messages = _.clone( + this.messaging.publicLivechatGlobal.publicLivechat.widget.getMessages() + ); const modeOptions = this._enabledOptions; @@ -108,14 +113,14 @@ const PublicLivechatView = Widget.extend({ // and in the same document (users can now post message in documents // directly from a channel that follows it) let prevMessage; - for (let message of messages) { + for (const message of messages) { if ( // is first message of thread !prevMessage || // more than 1 min. elasped - (Math.abs(message.getDate().diff(prevMessage.getDate())) > 60000) || - prevMessage.getType() !== 'comment' || - message.getType() !== 'comment' || + Math.abs(message.getDate().diff(prevMessage.getDate())) > 60000 || + prevMessage.getType() !== "comment" || + message.getType() !== "comment" || // from a different author prevMessage.getAuthorID() !== message.getAuthorID() ) { @@ -130,17 +135,19 @@ const PublicLivechatView = Widget.extend({ messages.reverse(); } - this.$el.html(QWeb.render('im_livechat.legacy.mail.widget.Thread', { - displayAuthorMessages, - options, - ORDER, - dateFormat: time.getLangDatetimeFormat(), - widget: this, - })); + this.$el.html( + QWeb.render("im_livechat.legacy.mail.widget.Thread", { + displayAuthorMessages, + options, + ORDER, + dateFormat: time.getLangDatetimeFormat(), + widget: this, + }) + ); - for (let message of messages) { + for (const message of messages) { const $message = this.$('.o_thread_message[data-message-id="' + message.getID() + '"]'); - $message.find('.o_mail_timestamp').data('date', message.getDate()); + $message.find(".o_mail_timestamp").data("date", message.getDate()); this._insertReadMore($message); } @@ -161,7 +168,7 @@ const PublicLivechatView = Widget.extend({ * @see /mail/init_messaging */ renderLoading() { - this.$el.html(QWeb.render('im_livechat.legacy.mail.widget.ThreadLoading')); + this.$el.html(QWeb.render("im_livechat.legacy.mail.widget.ThreadLoading")); }, //-------------------------------------------------------------------------- @@ -177,7 +184,7 @@ const PublicLivechatView = Widget.extend({ * * @return {boolean} */ - isAtBottom() { + isAtBottom() { const fullHeight = this.el.scrollHeight; const topHiddenHeight = this.$el.scrollTop(); const visibleHeight = this.$el.outerHeight(); @@ -197,14 +204,15 @@ const PublicLivechatView = Widget.extend({ * @param {integer} [options.duration] * @param {boolean} [options.onlyIfNecessary] */ - scrollToMessage(options) { + scrollToMessage(options) { const $target = this.$('.o_thread_message[data-message-id="' + options.messageID + '"]'); if (options.onlyIfNecessary) { const delta = $target.parent().height() - $target.height(); - let offset = delta < 0 ? - 0 : - delta - ($target.offset().top - $target.offsetParent().offset().top); - offset = - Math.min(offset, 0); + let offset = + delta < 0 + ? 0 + : delta - ($target.offset().top - $target.offsetParent().offset().top); + offset = -Math.min(offset, 0); this.$el.scrollTo("+=" + offset + "px", options.duration); } else if ($target.length) { this.$el.scrollTo($target); @@ -229,7 +237,7 @@ const PublicLivechatView = Widget.extend({ * Unselect the selected message */ unselectMessage() { - this.$('.o_thread_message').removeClass('o_thread_selected_message'); + this.$(".o_thread_message").removeClass("o_thread_selected_message"); this._selectedMessageID = null; }, @@ -247,43 +255,34 @@ const PublicLivechatView = Widget.extend({ * @private * @param {jQuery} $element */ - _insertReadMore($element) { - + _insertReadMore($element) { const groups = []; let readMoreNodes; // nodeType 1: element_node // nodeType 3: text_node - const $children = $element.contents() - .filter(function () { - return this.nodeType === 1 || - this.nodeType === 3 && - this.nodeValue.trim(); - }); + const $children = $element.contents().filter(function () { + return this.nodeType === 1 || (this.nodeType === 3 && this.nodeValue.trim()); + }); - for (let child of $children) { + for (const child of $children) { let $child = $(child); // Hide Text nodes if "stopSpelling" - if ( - child.nodeType === 3 && - $child.prevAll('[id*="stopSpelling"]').length > 0 - ) { + if (child.nodeType === 3 && $child.prevAll('[id*="stopSpelling"]').length > 0) { // Convert Text nodes to Element nodes - $child = $('', { + $child = $("", { text: child.textContent, - 'data-o-mail-quote': '1', + "data-o-mail-quote": "1", }); child.parentNode.replaceChild($child[0], child); } // Create array for each 'read more' with nodes to toggle if ( - $child.attr('data-o-mail-quote') || - ( - $child.get(0).nodeName === 'BR' && - $child.prev('[data-o-mail-quote="1"]').length > 0 - ) + $child.attr("data-o-mail-quote") || + ($child.get(0).nodeName === "BR" && + $child.prev('[data-o-mail-quote="1"]').length > 0) ) { if (!readMoreNodes) { readMoreNodes = []; @@ -297,11 +296,11 @@ const PublicLivechatView = Widget.extend({ } } - for (let group of groups) { + for (const group of groups) { // Insert link just before the first node - const $readMore = $('', { - class: 'o_mail_read_more', - href: '#', + const $readMore = $("", { + class: "o_mail_read_more", + href: "#", text: READ_MORE, }).insertBefore(group[0]); @@ -310,7 +309,7 @@ const PublicLivechatView = Widget.extend({ $readMore.click(function (e) { e.preventDefault(); isReadMore = !isReadMore; - for (let $child of group) { + for (const $child of group) { $child.hide(); $child.toggle(!isReadMore); } @@ -325,20 +324,24 @@ const PublicLivechatView = Widget.extend({ * @param {string} options.model * @param {integer} options.id */ - _redirect: _.debounce(function (options) { - if ('channelID' in options) { - this.trigger('redirect_to_channel', options.channelID); - } else { - this.trigger('redirect', options.model, options.id); - } - }, 500, true), + _redirect: _.debounce( + function (options) { + if ("channelID" in options) { + this.trigger("redirect_to_channel", options.channelID); + } else { + this.trigger("redirect", options.model, options.id); + } + }, + 500, + true + ), /** * @private */ - _updateTimestamps() { + _updateTimestamps() { const isAtBottom = this.isAtBottom(); - this.$('.o_mail_timestamp').each(function () { - const date = $(this).data('date'); + this.$(".o_mail_timestamp").each(function () { + const date = $(this).data("date"); $(this).text(mailUtils.timeFromNow(date)); }); if (isAtBottom && !this.isAtBottom()) { @@ -356,7 +359,7 @@ const PublicLivechatView = Widget.extend({ _onClick() { if (this._selectedMessageID) { this.unselectMessage(); - this.trigger('unselect_message'); + this.trigger("unselect_message"); } }, /** @@ -371,26 +374,26 @@ const PublicLivechatView = Widget.extend({ * @param {MouseEvent} ev */ _onClickMessage(ev) { - $(ev.currentTarget).toggleClass('o_thread_selected_message'); + $(ev.currentTarget).toggleClass("o_thread_selected_message"); }, /** * @private * @param {MouseEvent} ev */ - _onClickMessageNeedaction(ev) { - const messageID = $(ev.currentTarget).data('message-id'); - this.trigger('mark_as_read', messageID); + _onClickMessageNeedaction(ev) { + const messageID = $(ev.currentTarget).data("message-id"); + this.trigger("mark_as_read", messageID); }, /** * @private * @param {MouseEvent} ev */ _onClickMessageNotificationError(ev) { - const messageID = $(ev.currentTarget).data('message-id'); - this.do_action('mail.mail_resend_message_action', { + const messageID = $(ev.currentTarget).data("message-id"); + this.do_action("mail.mail_resend_message_action", { additional_context: { mail_message_to_resend: messageID, - } + }, }); }, /** @@ -398,20 +401,21 @@ const PublicLivechatView = Widget.extend({ * @param {MouseEvent} ev */ _onClickMessageReply(ev) { - this._selectedMessageID = $(ev.currentTarget).data('message-id'); - this.$('.o_thread_message').removeClass('o_thread_selected_message'); - this.$('.o_thread_message[data-message-id="' + this._selectedMessageID + '"]') - .addClass('o_thread_selected_message'); - this.trigger('select_message', this._selectedMessageID); + this._selectedMessageID = $(ev.currentTarget).data("message-id"); + this.$(".o_thread_message").removeClass("o_thread_selected_message"); + this.$('.o_thread_message[data-message-id="' + this._selectedMessageID + '"]').addClass( + "o_thread_selected_message" + ); + this.trigger("select_message", this._selectedMessageID); ev.stopPropagation(); }, /** * @private * @param {MouseEvent} ev */ - _onClickMessageStar(ev) { - const messageID = $(ev.currentTarget).data('message-id'); - this.trigger('toggle_star_status', messageID); + _onClickMessageStar(ev) { + const messageID = $(ev.currentTarget).data("message-id"); + this.trigger("toggle_star_status", messageID); }, /** * @private @@ -419,18 +423,18 @@ const PublicLivechatView = Widget.extend({ */ _onClickRedirect(ev) { // ignore inherited branding - if ($(ev.target).data('oe-field') !== undefined) { + if ($(ev.target).data("oe-field") !== undefined) { return; } - const id = $(ev.target).data('oe-id'); + const id = $(ev.target).data("oe-id"); if (id) { ev.preventDefault(); - const model = $(ev.target).data('oe-model'); + const model = $(ev.target).data("oe-model"); let options; - if (model && (model !== 'mail.channel')) { + if (model && model !== "mail.channel") { options = { model, - id + id, }; } else { options = { channelID: id }; @@ -442,7 +446,7 @@ const PublicLivechatView = Widget.extend({ * @private */ _onClickShowMore() { - this.trigger('load_more_messages'); + this.trigger("load_more_messages"); }, }); 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 10a27b45aa9..926ae6a3fa5 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,11 +1,11 @@ /** @odoo-module **/ -import config from 'web.config'; -import { _t, qweb } from 'web.core'; -import Widget from 'web.Widget'; +import config from "web.config"; +import { _t, qweb } from "web.core"; +import Widget from "web.Widget"; -import {unaccent} from 'web.utils'; -import {setCookie} from 'web.utils.cookies'; +import { unaccent } from "web.utils"; +import { setCookie } from "web.utils.cookies"; /** * This is the widget that represent windows of livechat in the frontend. @@ -14,17 +14,17 @@ import {setCookie} from 'web.utils.cookies'; */ const PublicLivechatWindow = Widget.extend({ FOLD_ANIMATION_DURATION: 200, // duration in ms for (un)fold transition - HEIGHT_OPEN: '400px', // height in px of thread window when open - HEIGHT_FOLDED: '34px', // height, in px, of thread window when folded - template: 'im_livechat.legacy.PublicLivechatWindow', + HEIGHT_OPEN: "400px", // height in px of thread window when open + HEIGHT_FOLDED: "34px", // height, in px, of thread window when folded + template: "im_livechat.legacy.PublicLivechatWindow", events: { - 'click .o_thread_window_close': '_onClickClose', - 'click .o_thread_window_header': '_onClickFold', - 'click .o_composer_text_field': '_onComposerClick', - 'click .o_mail_thread': '_onThreadWindowClicked', - 'keydown .o_composer_text_field': '_onKeydown', - 'keypress .o_composer_text_field': '_onKeypress', - 'input .o_composer_text_field': '_onInput', + "click .o_thread_window_close": "_onClickClose", + "click .o_thread_window_header": "_onClickFold", + "click .o_composer_text_field": "_onComposerClick", + "click .o_mail_thread": "_onThreadWindowClicked", + "keydown .o_composer_text_field": "_onKeydown", + "keypress .o_composer_text_field": "_onKeypress", + "input .o_composer_text_field": "_onInput", }, /** * @param {Widget} parent @@ -42,29 +42,40 @@ const PublicLivechatWindow = Widget.extend({ * @return {Promise} */ async start() { - this.$input = this.$('.o_composer_text_field'); - this.$header = this.$('.o_thread_window_header'); + this.$input = this.$(".o_composer_text_field"); + this.$header = this.$(".o_thread_window_header"); // animate the (un)folding of thread windows - this.$el.css({ transition: 'height ' + this.FOLD_ANIMATION_DURATION + 'ms linear' }); + this.$el.css({ transition: "height " + this.FOLD_ANIMATION_DURATION + "ms linear" }); if (this.messaging.publicLivechatGlobal.publicLivechat.isFolded) { - this.$el.css('height', this.HEIGHT_FOLDED); + this.$el.css("height", this.HEIGHT_FOLDED); } else { this._focusInput(); } - const def = this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.replace(this.$('.o_thread_window_content')).then(() => { - this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.$el.on('scroll', this, this._debouncedOnScroll); - }); + const def = this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget + .replace(this.$(".o_thread_window_content")) + .then(() => { + this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.$el.on( + "scroll", + this, + this._debouncedOnScroll + ); + }); await Promise.all([this._super(), def]); if (this.messaging.publicLivechatGlobal.livechatButtonView.headerBackgroundColor) { - this.$('.o_thread_window_header').css('background-color', this.messaging.publicLivechatGlobal.livechatButtonView.headerBackgroundColor); + this.$(".o_thread_window_header").css( + "background-color", + this.messaging.publicLivechatGlobal.livechatButtonView.headerBackgroundColor + ); } if (this.messaging.publicLivechatGlobal.livechatButtonView.titleColor) { - this.$('.o_thread_window_header').css('color', this.messaging.publicLivechatGlobal.livechatButtonView.titleColor); + this.$(".o_thread_window_header").css( + "color", + this.messaging.publicLivechatGlobal.livechatButtonView.titleColor + ); } }, - //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- @@ -73,10 +84,14 @@ const PublicLivechatWindow = Widget.extend({ * @override */ close() { - const isComposerDisabled = this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_thread_composer input').prop('disabled'); - const shouldAskFeedback = !isComposerDisabled && this.messaging.publicLivechatGlobal.messages.find(function (message) { - return message.id !== '_welcome'; - }); + const isComposerDisabled = this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_thread_composer input") + .prop("disabled"); + const shouldAskFeedback = + !isComposerDisabled && + this.messaging.publicLivechatGlobal.messages.find(function (message) { + return message.id !== "_welcome"; + }); if (shouldAskFeedback) { this.messaging.publicLivechatGlobal.chatWindow.widget.toggleFold(false); this.messaging.publicLivechatGlobal.livechatButtonView.askFeedback(); @@ -99,7 +114,9 @@ const PublicLivechatWindow = Widget.extend({ */ render() { this.renderHeader(); - this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.render({ displayLoadMore: false }); + this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.render({ + displayLoadMore: false, + }); }, /** * Render the header of this thread window. @@ -109,7 +126,9 @@ const PublicLivechatWindow = Widget.extend({ * @private */ renderHeader() { - this.$header.html(qweb.render('im_livechat.legacy.PublicLivechatWindow.HeaderContent', { widget: this })); + this.$header.html( + qweb.render("im_livechat.legacy.PublicLivechatWindow.HeaderContent", { widget: this }) + ); }, /** @@ -126,9 +145,10 @@ const PublicLivechatWindow = Widget.extend({ */ adjustPosition() { const cssProps = { bottom: 0 }; - cssProps[this.messaging.locale.textDirection === 'rtl' ? 'left' : 'right'] = 0; + cssProps[this.messaging.locale.textDirection === "rtl" ? "left" : "right"] = 0; if (!config.device.isMobile) { - const margin_dir = _t.database.parameters.direction === "rtl" ? "margin-left" : "margin-right"; + const margin_dir = + _t.database.parameters.direction === "rtl" ? "margin-left" : "margin-right"; cssProps[margin_dir] = $.position.scrollbarWidth(); } this.$el.css(cssProps); @@ -140,7 +160,9 @@ const PublicLivechatWindow = Widget.extend({ * @param {$.Element} $element */ replaceContentWith($element) { - $element.replace(this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.$el); + $element.replace( + this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.$el + ); }, /** * Toggle the fold state of this thread window. Also update the fold state @@ -158,7 +180,17 @@ const PublicLivechatWindow = Widget.extend({ } this.messaging.publicLivechatGlobal.publicLivechat.update({ isFolded: folded }); if (this.messaging.publicLivechatGlobal.publicLivechat.operator) { - setCookie('im_livechat_session', unaccent(JSON.stringify(this.messaging.publicLivechatGlobal.publicLivechat.widget.toData()), true), 60 * 60, 'required'); + setCookie( + "im_livechat_session", + unaccent( + JSON.stringify( + this.messaging.publicLivechatGlobal.publicLivechat.widget.toData() + ), + true + ), + 60 * 60, + "required" + ); } this.updateVisualFoldState(); }, @@ -172,7 +204,9 @@ const PublicLivechatWindow = Widget.extend({ this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.scrollToBottom(); this._focusInput(); } - const height = this.messaging.publicLivechatGlobal.publicLivechat.isFolded ? this.HEIGHT_FOLDED : this.HEIGHT_OPEN; + const height = this.messaging.publicLivechatGlobal.publicLivechat.isFolded + ? this.HEIGHT_FOLDED + : this.HEIGHT_OPEN; this.$el.css({ height }); }, @@ -188,10 +222,7 @@ const PublicLivechatWindow = Widget.extend({ * Set the focus on the input of the window */ _focusInput() { - if ( - config.device.touch && - config.device.size_class <= config.device.SIZES.SM - ) { + if (config.device.touch && config.device.size_class <= config.device.SIZES.SM) { return; } this.$input.focus(); @@ -204,7 +235,7 @@ const PublicLivechatWindow = Widget.extend({ * @returns {boolean} */ _hasFocus() { - return this.$input.is(':focus'); + return this.$input.is(":focus"); }, /** * Post a message on this thread window, and auto-scroll to the bottom of @@ -222,7 +253,8 @@ const PublicLivechatWindow = Widget.extend({ if (!this.messaging.publicLivechatGlobal.publicLivechat.operator) { return; } - this.messaging.publicLivechatGlobal.publicLivechat.widget.postMessage(messageData) + this.messaging.publicLivechatGlobal.publicLivechat.widget + .postMessage(messageData) .then(() => { this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.scrollToBottom(); }); @@ -269,7 +301,7 @@ const PublicLivechatWindow = Widget.extend({ * @param {Event} ev */ _onComposerClick(ev) { - if ($(ev.target).closest('a, button').length) { + if ($(ev.target).closest("a, button").length) { return; } this._focusInput(); @@ -281,7 +313,9 @@ const PublicLivechatWindow = Widget.extend({ */ _onInput() { const isTyping = this.$input.val().length > 0; - this.messaging.publicLivechatGlobal.publicLivechat.widget.setMyselfTyping({ typing: isTyping }); + this.messaging.publicLivechatGlobal.publicLivechat.widget.setMyselfTyping({ + typing: isTyping, + }); }, /** * Called when typing something on the composer of this thread window. @@ -299,7 +333,7 @@ const PublicLivechatWindow = Widget.extend({ attachment_ids: [], partner_ids: [], }; - this.$input.val(''); + this.$input.val(""); if (content) { this._postMessage(messageData); } diff --git a/addons/im_livechat/static/src/models/channel.js b/addons/im_livechat/static/src/models/channel.js index ab568902cab..c359a542ef7 100644 --- a/addons/im_livechat/static/src/models/channel.js +++ b/addons/im_livechat/static/src/models/channel.js @@ -1,15 +1,15 @@ /** @odoo-module **/ -import { attr, one, Patch } from '@mail/model'; +import { attr, one, Patch } from "@mail/model"; Patch({ - name: 'Channel', + name: "Channel", fields: { - anonymous_country: one('Country'), + anonymous_country: one("Country"), anonymous_name: attr(), discussSidebarCategory: { compute() { - if (this.channel_type === 'livechat') { + if (this.channel_type === "livechat") { return this.messaging.discuss.categoryLivechat; } return this._super(); @@ -20,12 +20,16 @@ Patch({ if (!this.thread) { return; } - if (this.channel_type === 'livechat' && this.correspondent) { + if (this.channel_type === "livechat" && this.correspondent) { if (!this.correspondent.is_public && this.correspondent.country) { - return `${this.thread.getMemberName(this.correspondent.persona)} (${this.correspondent.country.name})`; + return `${this.thread.getMemberName(this.correspondent.persona)} (${ + this.correspondent.country.name + })`; } if (this.anonymous_country) { - return `${this.thread.getMemberName(this.correspondent.persona)} (${this.anonymous_country.name})`; + return `${this.thread.getMemberName(this.correspondent.persona)} (${ + this.anonymous_country.name + })`; } return this.thread.getMemberName(this.correspondent.persona); } diff --git a/addons/im_livechat/static/src/models/channel_preview_view.js b/addons/im_livechat/static/src/models/channel_preview_view.js index fcae7576645..8afa9b0a103 100644 --- a/addons/im_livechat/static/src/models/channel_preview_view.js +++ b/addons/im_livechat/static/src/models/channel_preview_view.js @@ -1,14 +1,14 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'ChannelPreviewView', + name: "ChannelPreviewView", fields: { imageUrl: { compute() { - if (this.channel.channel_type === 'livechat') { - return '/mail/static/src/img/smiley/avatar.jpg'; + if (this.channel.channel_type === "livechat") { + return "/mail/static/src/img/smiley/avatar.jpg"; } return this._super(); }, diff --git a/addons/im_livechat/static/src/models/chat_window.js b/addons/im_livechat/static/src/models/chat_window.js index 61cc5c699be..c506592df91 100644 --- a/addons/im_livechat/static/src/models/chat_window.js +++ b/addons/im_livechat/static/src/models/chat_window.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'ChatWindow', + name: "ChatWindow", recordMethods: { /** * @override @@ -12,7 +12,7 @@ Patch({ if ( this.thread && this.thread.channel && - this.thread.channel.channel_type === 'livechat' && + this.thread.channel.channel_type === "livechat" && this.thread.cache.isLoaded && this.thread.messages.length === 0 ) { diff --git a/addons/im_livechat/static/src/models/composer_view.js b/addons/im_livechat/static/src/models/composer_view.js index d8244d239b6..ae36a4c5787 100644 --- a/addons/im_livechat/static/src/models/composer_view.js +++ b/addons/im_livechat/static/src/models/composer_view.js @@ -1,13 +1,17 @@ /** @odoo-module **/ -import { clear, Patch } from '@mail/model'; +import { clear, Patch } from "@mail/model"; Patch({ - name: 'ComposerView', + name: "ComposerView", fields: { dropZoneView: { compute() { - if (this.composer.thread && this.composer.thread.channel && this.composer.thread.channel.channel_type === 'livechat') { + if ( + this.composer.thread && + this.composer.thread.channel && + this.composer.thread.channel.channel_type === "livechat" + ) { return clear(); } return this._super(); diff --git a/addons/im_livechat/static/src/models/discuss.js b/addons/im_livechat/static/src/models/discuss.js index ffaab45ed32..330d293e977 100644 --- a/addons/im_livechat/static/src/models/discuss.js +++ b/addons/im_livechat/static/src/models/discuss.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { one, Patch } from '@mail/model'; +import { one, Patch } from "@mail/model"; Patch({ - name: 'Discuss', + name: "Discuss", recordMethods: { /** * @override @@ -19,9 +19,9 @@ Patch({ /** * Discuss sidebar category for `livechat` channel threads. */ - categoryLivechat: one('DiscussSidebarCategory', { + categoryLivechat: one("DiscussSidebarCategory", { default: {}, - inverse: 'discussAsLivechat', + inverse: "discussAsLivechat", }), }, }); diff --git a/addons/im_livechat/static/src/models/discuss_sidebar_category.js b/addons/im_livechat/static/src/models/discuss_sidebar_category.js index 8a6838bdc3c..adc53a6ba57 100644 --- a/addons/im_livechat/static/src/models/discuss_sidebar_category.js +++ b/addons/im_livechat/static/src/models/discuss_sidebar_category.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { clear, one, Patch } from '@mail/model'; +import { clear, one, Patch } from "@mail/model"; Patch({ - name: 'DiscussSidebarCategory', + name: "DiscussSidebarCategory", fields: { categoryItemsOrderedByLastAction: { compute() { @@ -13,9 +13,9 @@ Patch({ return this._super(); }, }, - discussAsLivechat: one('Discuss', { + discussAsLivechat: one("Discuss", { identifying: true, - inverse: 'categoryLivechat', + inverse: "categoryLivechat", }), isServerOpen: { compute() { @@ -27,7 +27,8 @@ Patch({ return clear(); } if (this.discussAsLivechat) { - return this.messaging.currentUser.res_users_settings_id.is_discuss_sidebar_category_livechat_open; + return this.messaging.currentUser.res_users_settings_id + .is_discuss_sidebar_category_livechat_open; } return this._super(); }, @@ -51,7 +52,7 @@ Patch({ serverStateKey: { compute() { if (this.discussAsLivechat) { - return 'is_discuss_sidebar_category_livechat_open'; + return "is_discuss_sidebar_category_livechat_open"; } return this._super(); }, @@ -59,7 +60,7 @@ Patch({ supportedChannelTypes: { compute() { if (this.discussAsLivechat) { - return ['livechat']; + return ["livechat"]; } return this._super(); }, diff --git a/addons/im_livechat/static/src/models/discuss_sidebar_category_item.js b/addons/im_livechat/static/src/models/discuss_sidebar_category_item.js index ae0e88ac30c..b594c779e7d 100644 --- a/addons/im_livechat/static/src/models/discuss_sidebar_category_item.js +++ b/addons/im_livechat/static/src/models/discuss_sidebar_category_item.js @@ -1,13 +1,13 @@ /** @odoo-module **/ -import { clear, Patch } from '@mail/model'; +import { clear, Patch } from "@mail/model"; Patch({ - name: 'DiscussSidebarCategoryItem', + name: "DiscussSidebarCategoryItem", fields: { avatarUrl: { compute() { - if (this.channel.channel_type === 'livechat') { + if (this.channel.channel_type === "livechat") { if (this.channel.correspondent && !this.channel.correspondent.is_public) { return this.channel.correspondent.avatarUrl; } @@ -17,7 +17,7 @@ Patch({ }, categoryCounterContribution: { compute() { - if (this.channel.channel_type === 'livechat') { + if (this.channel.channel_type === "livechat") { return this.channel.localMessageUnreadCounter > 0 ? 1 : 0; } return this._super(); @@ -25,7 +25,7 @@ Patch({ }, counter: { compute() { - if (this.channel.channel_type === 'livechat') { + if (this.channel.channel_type === "livechat") { return this.channel.localMessageUnreadCounter; } return this._super(); @@ -33,7 +33,7 @@ Patch({ }, hasUnpinCommand: { compute() { - if (this.channel.channel_type === 'livechat') { + if (this.channel.channel_type === "livechat") { return !this.channel.localMessageUnreadCounter; } return this._super(); @@ -41,7 +41,7 @@ Patch({ }, threadIconView: { compute() { - if (this.channel.channel_type === 'livechat') { + if (this.channel.channel_type === "livechat") { return clear(); } return this._super(); diff --git a/addons/im_livechat/static/src/models/message.js b/addons/im_livechat/static/src/models/message.js index 62e85c51ee0..a2010ccc87d 100644 --- a/addons/im_livechat/static/src/models/message.js +++ b/addons/im_livechat/static/src/models/message.js @@ -1,13 +1,17 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'Message', + name: "Message", fields: { hasReactionIcon: { compute() { - if (this.originThread && this.originThread.channel && this.originThread.channel.channel_type === 'livechat') { + if ( + this.originThread && + this.originThread.channel && + this.originThread.channel.channel_type === "livechat" + ) { return false; } return this._super(); diff --git a/addons/im_livechat/static/src/models/message_action_list.js b/addons/im_livechat/static/src/models/message_action_list.js index a35dcf3fb1c..7f36c71ea60 100644 --- a/addons/im_livechat/static/src/models/message_action_list.js +++ b/addons/im_livechat/static/src/models/message_action_list.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { clear, Patch } from '@mail/model'; +import { clear, Patch } from "@mail/model"; Patch({ - name: 'MessageActionList', + name: "MessageActionList", fields: { actionReplyTo: { compute() { @@ -11,12 +11,12 @@ Patch({ this.message && this.message.originThread && this.message.originThread.channel && - this.message.originThread.channel.channel_type === 'livechat' + this.message.originThread.channel.channel_type === "livechat" ) { return clear(); } return this._super(); - } + }, }, }, }); diff --git a/addons/im_livechat/static/src/models/message_view.js b/addons/im_livechat/static/src/models/message_view.js index beacd7071ef..305ad3af37d 100644 --- a/addons/im_livechat/static/src/models/message_view.js +++ b/addons/im_livechat/static/src/models/message_view.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ name: "MessageView", diff --git a/addons/im_livechat/static/src/models/messaging.js b/addons/im_livechat/static/src/models/messaging.js index 221ce869c6b..c0cd92e1b4a 100644 --- a/addons/im_livechat/static/src/models/messaging.js +++ b/addons/im_livechat/static/src/models/messaging.js @@ -1,15 +1,15 @@ /** @odoo-module **/ -import { many, Patch } from '@mail/model'; +import { many, Patch } from "@mail/model"; Patch({ - name: 'Messaging', + name: "Messaging", fields: { /** * All pinned livechats that are known. */ - pinnedLivechats: many('Thread', { - inverse: 'messagingAsPinnedLivechat', + pinnedLivechats: many("Thread", { + inverse: "messagingAsPinnedLivechat", readonly: true, }), }, diff --git a/addons/im_livechat/static/src/models/messaging_initializer.js b/addons/im_livechat/static/src/models/messaging_initializer.js index a72cb051307..8da83889509 100644 --- a/addons/im_livechat/static/src/models/messaging_initializer.js +++ b/addons/im_livechat/static/src/models/messaging_initializer.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { insert, Patch } from '@mail/model'; +import { insert, Patch } from "@mail/model"; Patch({ - name: 'MessagingInitializer', + name: "MessagingInitializer", recordMethods: { /** * @override @@ -13,9 +13,9 @@ Patch({ this._super(); this.messaging.update({ commands: insert({ - channel_types: ['livechat'], + channel_types: ["livechat"], help: this.env._t("See 15 last visited pages"), - methodName: 'execute_command_history', + methodName: "execute_command_history", name: "history", }), }); diff --git a/addons/im_livechat/static/src/models/mobile_messaging_navbar_view.js b/addons/im_livechat/static/src/models/mobile_messaging_navbar_view.js index accabb33ac3..d3bf6371cae 100644 --- a/addons/im_livechat/static/src/models/mobile_messaging_navbar_view.js +++ b/addons/im_livechat/static/src/models/mobile_messaging_navbar_view.js @@ -1,19 +1,22 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'MobileMessagingNavbarView', + name: "MobileMessagingNavbarView", fields: { tabs: { compute() { const res = this._super(); if (this.messaging.pinnedLivechats.length > 0) { - return [...res, { - icon: 'fa fa-comments', - id: 'livechat', - label: this.env._t("Livechat"), - }]; + return [ + ...res, + { + icon: "fa fa-comments", + id: "livechat", + label: this.env._t("Livechat"), + }, + ]; } return res; }, diff --git a/addons/im_livechat/static/src/models/notification_list_view.js b/addons/im_livechat/static/src/models/notification_list_view.js index fd10c7110fa..5064ae56278 100644 --- a/addons/im_livechat/static/src/models/notification_list_view.js +++ b/addons/im_livechat/static/src/models/notification_list_view.js @@ -1,16 +1,15 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'NotificationListView', + name: "NotificationListView", fields: { filteredChannels: { compute() { - if (this.filter === 'livechat') { - return this.messaging.models['Channel'].all(channel => - channel.channel_type === 'livechat' && - channel.thread.isPinned + if (this.filter === "livechat") { + return this.messaging.models["Channel"].all( + (channel) => channel.channel_type === "livechat" && channel.thread.isPinned ); } return this._super(); diff --git a/addons/im_livechat/static/src/models/partner.js b/addons/im_livechat/static/src/models/partner.js index a56dfb94360..a40bf294b9f 100644 --- a/addons/im_livechat/static/src/models/partner.js +++ b/addons/im_livechat/static/src/models/partner.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { attr, Patch } from '@mail/model'; +import { attr, Patch } from "@mail/model"; Patch({ - name: 'Partner', + name: "Partner", fields: { /** * States the specific name of this partner in the context of livechat. diff --git a/addons/im_livechat/static/src/models/res_users_settings.js b/addons/im_livechat/static/src/models/res_users_settings.js index 401747874c2..6855d3eb9e9 100644 --- a/addons/im_livechat/static/src/models/res_users_settings.js +++ b/addons/im_livechat/static/src/models/res_users_settings.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { attr, Patch } from '@mail/model'; +import { attr, Patch } from "@mail/model"; Patch({ - name: 'res.users.settings', + name: "res.users.settings", fields: { is_discuss_sidebar_category_livechat_open: attr({ default: true, diff --git a/addons/im_livechat/static/src/models/thread.js b/addons/im_livechat/static/src/models/thread.js index 01ca49f7ffd..abfadf41bd7 100644 --- a/addons/im_livechat/static/src/models/thread.js +++ b/addons/im_livechat/static/src/models/thread.js @@ -1,18 +1,29 @@ /** @odoo-module **/ -import { clear, one, Patch } from '@mail/model'; +import { clear, one, Patch } from "@mail/model"; Patch({ - name: 'Thread', + name: "Thread", recordMethods: { /** * @override */ getMemberName(persona) { - if (this.channel && this.channel.channel_type === 'livechat' && persona.partner && persona.partner.user_livechat_username) { + if ( + this.channel && + this.channel.channel_type === "livechat" && + persona.partner && + persona.partner.user_livechat_username + ) { return persona.partner.user_livechat_username; } - if (this.channel && this.channel.channel_type === 'livechat' && persona.partner && persona.partner.is_public && this.channel.anonymous_name) { + if ( + this.channel && + this.channel.channel_type === "livechat" && + persona.partner && + persona.partner.is_public && + this.channel.anonymous_name + ) { return this.channel.anonymous_name; } return this._super(persona); @@ -21,7 +32,7 @@ Patch({ fields: { hasInviteFeature: { compute() { - if (this.channel && this.channel.channel_type === 'livechat') { + if (this.channel && this.channel.channel_type === "livechat") { return true; } return this._super(); @@ -29,7 +40,7 @@ Patch({ }, hasMemberListFeature: { compute() { - if (this.channel && this.channel.channel_type === 'livechat') { + if (this.channel && this.channel.channel_type === "livechat") { return true; } return this._super(); @@ -37,7 +48,7 @@ Patch({ }, isChatChannel: { compute() { - if (this.channel && this.channel.channel_type === 'livechat') { + if (this.channel && this.channel.channel_type === "livechat") { return true; } return this._super(); @@ -46,14 +57,19 @@ Patch({ /** * If set, current thread is a livechat. */ - messagingAsPinnedLivechat: one('Messaging', { + messagingAsPinnedLivechat: one("Messaging", { compute() { - if (!this.messaging || !this.channel || this.channel.channel_type !== 'livechat' || !this.isPinned) { + if ( + !this.messaging || + !this.channel || + this.channel.channel_type !== "livechat" || + !this.isPinned + ) { return clear(); } return this.messaging; }, - inverse: 'pinnedLivechats', + inverse: "pinnedLivechats", }), }, }); diff --git a/addons/im_livechat/static/src/models/thread_icon_view.js b/addons/im_livechat/static/src/models/thread_icon_view.js index e73bdf9042f..fae86707bbf 100644 --- a/addons/im_livechat/static/src/models/thread_icon_view.js +++ b/addons/im_livechat/static/src/models/thread_icon_view.js @@ -1,15 +1,15 @@ /** @odoo-module **/ -import { Patch } from '@mail/model'; +import { Patch } from "@mail/model"; Patch({ - name: 'ThreadIconView', + name: "ThreadIconView", fields: { threadTypingIconView: { compute() { if ( this.thread.channel && - this.thread.channel.channel_type === 'livechat' && + this.thread.channel.channel_type === "livechat" && this.thread.orderedOtherTypingMembers.length > 0 ) { return {}; diff --git a/addons/im_livechat/static/src/public/main.js b/addons/im_livechat/static/src/public/main.js index f9f6ed4ec71..59b9f53107d 100644 --- a/addons/im_livechat/static/src/public/main.js +++ b/addons/im_livechat/static/src/public/main.js @@ -1,24 +1,26 @@ /** @odoo-module **/ -import { publicLivechatService } from '@im_livechat/services/public_livechat_service'; -import { isAvailable, options, serverUrl } from '@im_livechat/livechat_data'; +import { publicLivechatService } from "@im_livechat/services/public_livechat_service"; +import { isAvailable, options, serverUrl } from "@im_livechat/livechat_data"; -import { messagingService } from '@mail/services/messaging_service'; -import { makeMessagingToLegacyEnv } from '@mail/utils/make_messaging_to_legacy_env'; +import { messagingService } from "@mail/services/messaging_service"; +import { makeMessagingToLegacyEnv } from "@mail/utils/make_messaging_to_legacy_env"; -import { registry } from '@web/core/registry'; +import { registry } from "@web/core/registry"; const messagingValuesService = { start() { return { publicLivechatGlobal: { isAvailable, options, serverUrl }, }; - } + }, }; -const serviceRegistry = registry.category('services'); -serviceRegistry.add('messaging', messagingService); -serviceRegistry.add('messagingValues', messagingValuesService); -serviceRegistry.add('public_livechat_service', publicLivechatService); +const serviceRegistry = registry.category("services"); +serviceRegistry.add("messaging", messagingService); +serviceRegistry.add("messagingValues", messagingValuesService); +serviceRegistry.add("public_livechat_service", publicLivechatService); -registry.category('wowlToLegacyServiceMappers').add('make_messaging_to_legacy_env', makeMessagingToLegacyEnv); +registry + .category("wowlToLegacyServiceMappers") + .add("make_messaging_to_legacy_env", makeMessagingToLegacyEnv); diff --git a/addons/im_livechat/static/src/public/session.js b/addons/im_livechat/static/src/public/session.js index 850087f38f5..7853ba0eeae 100644 --- a/addons/im_livechat/static/src/public/session.js +++ b/addons/im_livechat/static/src/public/session.js @@ -1,7 +1,6 @@ -odoo.define('web.session', function (require) { - - const Session = require('web.Session'); - const { serverUrl } = require('@im_livechat/livechat_data'); +odoo.define("web.session", function (require) { + const Session = require("web.Session"); + const { serverUrl } = require("@im_livechat/livechat_data"); return new Session(undefined, serverUrl, { use_cors: true }); }); diff --git a/addons/im_livechat/static/src/public_models/chatbot.js b/addons/im_livechat/static/src/public_models/chatbot.js index 55ca07f48e6..5ecdbb04b3c 100644 --- a/addons/im_livechat/static/src/public_models/chatbot.js +++ b/addons/im_livechat/static/src/public_models/chatbot.js @@ -1,12 +1,12 @@ /** @odoo-module **/ -import { attr, one, clear, increment, Model } from '@mail/model'; +import { attr, one, clear, increment, Model } from "@mail/model"; -import { qweb } from 'web.core'; -import { Markup } from 'web.utils'; +import { qweb } from "web.core"; +import { Markup } from "web.utils"; Model({ - name: 'Chatbot', + name: "Chatbot", recordMethods: { /** * Add message posted by the bot into the conversation. @@ -18,8 +18,13 @@ Model({ addMessage(message, options) { message.body = Markup(message.body); this.messaging.publicLivechatGlobal.livechatButtonView.addMessage(message, options); - if (this.messaging.publicLivechatGlobal.publicLivechat.isFolded || !this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.isAtBottom()) { - this.messaging.publicLivechatGlobal.publicLivechat.update({ unreadCounter: increment() }); + if ( + this.messaging.publicLivechatGlobal.publicLivechat.isFolded || + !this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.isAtBottom() + ) { + this.messaging.publicLivechatGlobal.publicLivechat.update({ + unreadCounter: increment(), + }); } if (!options || !options.skipRenderMessages) { @@ -40,15 +45,24 @@ Model({ // handle the display return; } - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_composer_text_field').addClass('d-none'); - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_end').show(); - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_restart').one('click', this.messaging.publicLivechatGlobal.livechatButtonView.onChatbotRestartScript); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_composer_text_field") + .addClass("d-none"); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_end") + .show(); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_restart") + .one( + "click", + this.messaging.publicLivechatGlobal.livechatButtonView.onChatbotRestartScript + ); }, onKeydownInput() { if ( this.currentStep && this.currentStep.data && - this.currentStep.data.chatbot_step_type === 'free_input_multi' + this.currentStep.data.chatbot_step_type === "free_input_multi" ) { this.debouncedAwaitUserInput(); } @@ -75,14 +89,14 @@ Model({ } const postedWelcomeMessages = await this.messaging.rpc({ - route: '/chatbot/post_welcome_steps', + route: "/chatbot/post_welcome_steps", params: { channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, chatbot_script_id: this.scriptId, }, }); - const welcomeMessagesIds = welcomeMessages.map(welcomeMessage => welcomeMessage.id); + const welcomeMessagesIds = welcomeMessages.map((welcomeMessage) => welcomeMessage.id); this.messaging.publicLivechatGlobal.update({ messages: this.messaging.publicLivechatGlobal.messages.filter((message) => { !welcomeMessagesIds.includes(message.id); @@ -128,7 +142,7 @@ Model({ if (this.shouldEndScript) { this.endScript(); } else if ( - this.currentStep.data.chatbot_step_type === 'forward_operator' && + this.currentStep.data.chatbot_step_type === "forward_operator" && this.currentStep.data.chatbot_operator_found ) { this.messaging.publicLivechatGlobal.chatWindow.enableInput(); @@ -137,17 +151,14 @@ Model({ // user has already typed a message in -> trigger next step this.setIsTyping(); this.update({ - nextStepTimeout: setTimeout( - this.triggerNextStep, - this.messageDelay, - ), + nextStepTimeout: setTimeout(this.triggerNextStep, this.messageDelay), }); } else { this.messaging.publicLivechatGlobal.chatWindow.enableInput(); } } else { let triggerNextStep = true; - if (this.currentStep.data.chatbot_step_type === 'question_selection') { + if (this.currentStep.data.chatbot_step_type === "question_selection") { if (!this.messaging.publicLivechatGlobal.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 @@ -157,7 +168,11 @@ Model({ if (triggerNextStep) { let nextStepDelay = this.messageDelay; - if (this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_typing').length !== 0) { + if ( + this.messaging.publicLivechatGlobal.chatWindow.widget.$( + ".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 // e.g: previous step was "forward_operator" and no-one is available @@ -168,16 +183,15 @@ Model({ } this.update({ - nextStepTimeout: setTimeout( - this.triggerNextStep, - nextStepDelay, - ), + nextStepTimeout: setTimeout(this.triggerNextStep, nextStepDelay), }); } } if (!this.hasRestartButton) { - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_main_restart').addClass('d-none'); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_main_restart") + .addClass("d-none"); } }, /** @@ -195,7 +209,10 @@ Model({ 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.sessionCookieKey) { + if ( + key.startsWith("im_livechat.chatbot.state.uuid_") && + key !== this.sessionCookieKey + ) { browserLocalStorage.removeItem(key); } } @@ -213,10 +230,14 @@ Model({ * anyway in that case, since it's stored into a cookie). */ saveSession() { - localStorage.setItem('im_livechat.chatbot.state.uuid_' + this.messaging.publicLivechatGlobal.publicLivechat.uuid, JSON.stringify({ - '_chatbot': this.data, - '_chatbotCurrentStep': this.currentStep.data, - })); + localStorage.setItem( + "im_livechat.chatbot.state.uuid_" + + this.messaging.publicLivechatGlobal.publicLivechat.uuid, + JSON.stringify({ + _chatbot: this.data, + _chatbotCurrentStep: this.currentStep.data, + }) + ); }, /** * Adds a small "is typing" animation into the chat window. @@ -225,28 +246,32 @@ Model({ */ setIsTyping(isWelcomeMessage = false) { if (this.messaging.publicLivechatGlobal.livechatButtonView.isTypingTimeout) { - clearTimeout(this.messaging.publicLivechatGlobal.livechatButtonView.isTypingTimeout); + clearTimeout( + this.messaging.publicLivechatGlobal.livechatButtonView.isTypingTimeout + ); } - this.messaging.publicLivechatGlobal.chatWindow.disableInput(''); + this.messaging.publicLivechatGlobal.chatWindow.disableInput(""); this.messaging.publicLivechatGlobal.livechatButtonView.update({ - isTypingTimeout: setTimeout( - () => { - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { - return; - } - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_mail_thread_content').append( - $(qweb.render('im_livechat.legacy.chatbot.is_typing_message', { - 'chatbotImageSrc': `/im_livechat/operator/${ - this.messaging.publicLivechatGlobal.publicLivechat.operator.id - }/avatar`, - 'chatbotName': this.name, - 'isWelcomeMessage': isWelcomeMessage, - })) + isTypingTimeout: setTimeout(() => { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { + return; + } + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_mail_thread_content") + .append( + $( + qweb.render("im_livechat.legacy.chatbot.is_typing_message", { + chatbotImageSrc: `/im_livechat/operator/${this.messaging.publicLivechatGlobal.publicLivechat.operator.id}/avatar`, + chatbotName: this.name, + isWelcomeMessage: isWelcomeMessage, + }) + ) ); - this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.scrollToBottom(); - }, - this.messageDelay / 3, - ), + this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.scrollToBottom(); + }, this.messageDelay / 3), }); }, /** @@ -254,14 +279,17 @@ Model({ * This will receive the next step and call step processing. */ async triggerNextStep() { - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { return; } let triggerNextStep = true; if ( this.currentStep && this.currentStep.data && - this.currentStep.data.chatbot_step_type === 'question_email' + this.currentStep.data.chatbot_step_type === "question_email" ) { triggerNextStep = await this.validateEmail(); } @@ -271,7 +299,7 @@ Model({ } const nextStep = await this.messaging.rpc({ - route: '/chatbot/step/trigger', + route: "/chatbot/step/trigger", params: { channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, chatbot_script_id: this.scriptId, @@ -307,8 +335,8 @@ Model({ * Returns a boolean stating whether the email was valid or not. */ async validateEmail() { - let emailValidResult = await this.messaging.rpc({ - route: '/chatbot/step/validate_email', + const emailValidResult = await this.messaging.rpc({ + route: "/chatbot/step/validate_email", params: { channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid }, }); @@ -347,10 +375,7 @@ Model({ } else { this.setIsTyping(); this.update({ - nextStepTimeout: setTimeout( - this.triggerNextStep, - this.messageDelay, - ) + nextStepTimeout: setTimeout(this.triggerNextStep, this.messageDelay), }); } } @@ -367,31 +392,25 @@ Model({ if (this.messaging.publicLivechatGlobal.isTestChatbot) { return this.messaging.publicLivechatGlobal.testChatbotData; } - if (this.state === 'init') { + if (this.state === "init") { return this.messaging.publicLivechatGlobal.rule.chatbot; } - if (this.state === 'welcome') { + if (this.state === "welcome") { return this.messaging.publicLivechatGlobal.livechatInit.rule.chatbot; } - if ( - this.state === 'restore_session' && - this.localStorageState - ) { + if (this.state === "restore_session" && this.localStorageState) { return this.localStorageState._chatbot; } return clear(); }, }), - currentStep: one('ChatbotStep', { - inverse: 'chabotOwner', + currentStep: one("ChatbotStep", { + inverse: "chabotOwner", }), debouncedAwaitUserInput: attr({ compute() { // debounced to let the user type several sentences, see 'Chatbot/awaitUserInput' for details - return _.debounce( - this.awaitUserInput, - this.awaitUserInputDebounceTime, - ); + return _.debounce(this.awaitUserInput, this.awaitUserInputDebounceTime); }, }), hasRestartButton: attr({ @@ -411,10 +430,8 @@ Model({ } return Boolean( !this.currentStep || - ( - this.currentStep.data.chatbot_step_type !== 'forward_operator' || + this.currentStep.data.chatbot_step_type !== "forward_operator" || !this.currentStep.data.chatbot_operator_found - ) ); }, default: false, @@ -424,13 +441,19 @@ Model({ if (this.messaging.publicLivechatGlobal.isTestChatbot) { return true; } - if (this.messaging.publicLivechatGlobal.rule && this.messaging.publicLivechatGlobal.rule.chatbot) { + if ( + this.messaging.publicLivechatGlobal.rule && + this.messaging.publicLivechatGlobal.rule.chatbot + ) { return true; } - if (this.messaging.publicLivechatGlobal.livechatInit && this.messaging.publicLivechatGlobal.livechatInit.rule.chatbot) { + if ( + this.messaging.publicLivechatGlobal.livechatInit && + this.messaging.publicLivechatGlobal.livechatInit.rule.chatbot + ) { return true; } - if (this.state === 'welcome') { + if (this.state === "welcome") { return true; } if (this.localStorageState) { @@ -446,10 +469,10 @@ Model({ return clear(); } return [ - 'question_phone', - 'question_email', - 'free_input_single', - 'free_input_multi', + "question_phone", + "question_email", + "free_input_single", + "free_input_multi", ].includes(this.currentStep.data.chatbot_step_type); }, default: false, @@ -492,9 +515,9 @@ Model({ }, default: 3500, // in milliseconds }), - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'chatbot', + inverse: "chatbot", }), scriptId: attr({ compute() { @@ -510,7 +533,10 @@ Model({ if (!this.messaging.publicLivechatGlobal.sessionCookie) { return clear(); } - return 'im_livechat.chatbot.state.uuid_' + JSON.parse(this.messaging.publicLivechatGlobal.sessionCookie).uuid; + return ( + "im_livechat.chatbot.state.uuid_" + + JSON.parse(this.messaging.publicLivechatGlobal.sessionCookie).uuid + ); }, }), shouldEndScript: attr({ @@ -532,21 +558,26 @@ Model({ if (this.currentStep.data.conversation_closed) { return true; } - if (this.currentStep.data.chatbot_step_is_last && - (this.currentStep.data.chatbot_step_type !== 'forward_operator' || - !this.currentStep.data.chatbot_operator_found) + if ( + this.currentStep.data.chatbot_step_is_last && + (this.currentStep.data.chatbot_step_type !== "forward_operator" || + !this.currentStep.data.chatbot_operator_found) ) { - if (this.currentStep.data.chatbot_step_type === 'question_email' - && !this.currentStep.data.is_email_valid + if ( + this.currentStep.data.chatbot_step_type === "question_email" && + !this.currentStep.data.is_email_valid ) { // email is not (yet) valid, let the user answer / try again return false; } else if ( (this.isExpectingUserInput || - this.currentStep.data.chatbot_step_type === 'question_selection') && + this.currentStep.data.chatbot_step_type === "question_selection") && this.messaging.publicLivechatGlobal.messages.length !== 0 ) { - if (this.messaging.publicLivechatGlobal.lastMessage.authorId !== this.messaging.publicLivechatGlobal.publicLivechat.operator.id) { + if ( + this.messaging.publicLivechatGlobal.lastMessage.authorId !== + this.messaging.publicLivechatGlobal.publicLivechat.operator.id + ) { // we are on the last step of the script, expect a user input and the user has // already answered // -> end the script @@ -564,11 +595,17 @@ Model({ }), state: attr({ compute() { - if (this.messaging.publicLivechatGlobal.rule && !!this.messaging.publicLivechatGlobal.rule.chatbot) { - return 'init'; + if ( + this.messaging.publicLivechatGlobal.rule && + !!this.messaging.publicLivechatGlobal.rule.chatbot + ) { + return "init"; } - if (this.messaging.publicLivechatGlobal.livechatInit && this.messaging.publicLivechatGlobal.livechatInit.rule.chatbot) { - return 'welcome'; + if ( + this.messaging.publicLivechatGlobal.livechatInit && + this.messaging.publicLivechatGlobal.livechatInit.rule.chatbot + ) { + return "welcome"; } if ( !this.messaging.publicLivechatGlobal.rule && @@ -577,7 +614,7 @@ Model({ this.sessionCookieKey && localStorage.getItem(this.sessionCookieKey) ) { - return 'restore_session'; + return "restore_session"; } return clear(); }, diff --git a/addons/im_livechat/static/src/public_models/chatbot_step.js b/addons/im_livechat/static/src/public_models/chatbot_step.js index 99b3e8c8f11..6c5f00478dc 100644 --- a/addons/im_livechat/static/src/public_models/chatbot_step.js +++ b/addons/im_livechat/static/src/public_models/chatbot_step.js @@ -1,13 +1,13 @@ /** @odoo-module **/ -import { attr, one, Model } from '@mail/model'; +import { attr, one, Model } from "@mail/model"; Model({ - name: 'ChatbotStep', + name: "ChatbotStep", fields: { - chabotOwner: one('Chatbot', { + chabotOwner: one("Chatbot", { identifying: true, - inverse: 'currentStep', + inverse: "currentStep", }), data: attr(), }, diff --git a/addons/im_livechat/static/src/public_models/livechat_button_view.js b/addons/im_livechat/static/src/public_models/livechat_button_view.js index a7f0551827a..d83cd2dc78b 100644 --- a/addons/im_livechat/static/src/public_models/livechat_button_view.js +++ b/addons/im_livechat/static/src/public_models/livechat_button_view.js @@ -1,14 +1,16 @@ /** @odoo-module **/ -import { attr, clear, one, Model } from '@mail/model'; +import { attr, clear, one, Model } from "@mail/model"; -import {getCookie, deleteCookie} from 'web.utils.cookies'; +import { getCookie, deleteCookie } from "web.utils.cookies"; Model({ - name: 'LivechatButtonView', + name: "LivechatButtonView", lifecycleHooks: { _created() { - this.update({ widget: this.env.services.public_livechat_service.mountLivechatButton() }); + this.update({ + widget: this.env.services.public_livechat_service.mountLivechatButton(), + }); }, _willDelete() { this.widget.destroy(); @@ -20,19 +22,27 @@ Model({ * @param {Object} [options={}] */ addMessage(data, options) { - const hasAlreadyMessage = _.some(this.messaging.publicLivechatGlobal.messages, function (msg) { - return data.id === msg.id; - }); + const hasAlreadyMessage = _.some( + this.messaging.publicLivechatGlobal.messages, + function (msg) { + return data.id === msg.id; + } + ); if (hasAlreadyMessage) { return; } - const message = this.messaging.models['PublicLivechatMessage'].insert({ + const message = this.messaging.models["PublicLivechatMessage"].insert({ data, id: data.id, }); - if (this.messaging.publicLivechatGlobal.publicLivechat && this.messaging.publicLivechatGlobal.publicLivechat.widget) { - this.messaging.publicLivechatGlobal.publicLivechat.widget.addMessage(message.widget); + if ( + this.messaging.publicLivechatGlobal.publicLivechat && + this.messaging.publicLivechatGlobal.publicLivechat.widget + ) { + this.messaging.publicLivechatGlobal.publicLivechat.widget.addMessage( + message.widget + ); } if (options && options.prepend) { @@ -46,7 +56,9 @@ Model({ } }, askFeedback() { - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_thread_composer input').prop('disabled', true); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_thread_composer input") + .prop("disabled", true); this.messaging.publicLivechatGlobal.update({ feedbackView: {} }); /** * When we enter the "ask feedback" process of the chat, we hide some elements that become @@ -59,19 +71,28 @@ Model({ this.messaging.publicLivechatGlobal.chatbot.currentStep.data.conversation_closed = true; this.messaging.publicLivechatGlobal.chatbot.saveSession(); } - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_main_restart').addClass('d-none'); - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_end').hide(); - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_composer_text_field') - .removeClass('d-none') - .val(''); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_main_restart") + .addClass("d-none"); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_end") + .hide(); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_composer_text_field") + .removeClass("d-none") + .val(""); }, /** * Restart the script and then trigger the "next step" (which will be the first of the script * in this case). */ async onChatbotRestartScript(ev) { - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_composer_text_field').removeClass('d-none'); - this.messaging.publicLivechatGlobal.chatWindow.widget.$('.o_livechat_chatbot_end').hide(); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_composer_text_field") + .removeClass("d-none"); + this.messaging.publicLivechatGlobal.chatWindow.widget + .$(".o_livechat_chatbot_end") + .hide(); if (this.messaging.publicLivechatGlobal.chatbot.nextStepTimeout) { clearTimeout(this.messaging.publicLivechatGlobal.chatbot.nextStepTimeout); @@ -82,7 +103,7 @@ Model({ } const postedMessage = await this.messaging.rpc({ - route: '/chatbot/restart', + route: "/chatbot/restart", params: { channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, chatbot_script_id: this.messaging.publicLivechatGlobal.chatbot.scriptId, @@ -98,24 +119,27 @@ Model({ this.messaging.publicLivechatGlobal.chatbot.update({ nextStepTimeout: setTimeout( this.messaging.publicLivechatGlobal.chatbot.triggerNextStep, - this.messaging.publicLivechatGlobal.chatbot.messageDelay, + this.messaging.publicLivechatGlobal.chatbot.messageDelay ), }); }, closeChat() { this.messaging.publicLivechatGlobal.update({ chatWindow: clear() }); - deleteCookie('im_livechat_session'); + deleteCookie("im_livechat_session"); }, /** * Called when the visitor leaves the livechat chatter the first time (first click on X button) * this will deactivate the mail_channel, notify operator that visitor has left the channel. */ leaveSession() { - const cookie = getCookie('im_livechat_session'); + const cookie = getCookie("im_livechat_session"); if (cookie) { const channel = JSON.parse(cookie); - this.messaging.rpc({ route: '/im_livechat/visitor_leave_session', params: { uuid: channel.uuid } }); - deleteCookie('im_livechat_session'); + this.messaging.rpc({ + route: "/im_livechat/visitor_leave_session", + params: { uuid: channel.uuid }, + }); + deleteCookie("im_livechat_session"); } }, openChat() { @@ -127,7 +151,7 @@ Model({ }, async openChatWindow() { this.messaging.publicLivechatGlobal.update({ chatWindow: {} }); - await this.messaging.publicLivechatGlobal.chatWindow.widget.appendTo($('body')); + await this.messaging.publicLivechatGlobal.chatWindow.widget.appendTo($("body")); this.messaging.publicLivechatGlobal.chatWindow.widget.adjustPosition(); this.widget.$el.hide(); this._openChatWindowChatbot(); @@ -156,27 +180,30 @@ Model({ this.addMessage(m); } this.openChat(); - } else if (!this.messaging.device.isSmall && this.messaging.publicLivechatGlobal.rule.action === 'auto_popup') { - const autoPopupCookie = getCookie('im_livechat_auto_popup'); + } else if ( + !this.messaging.device.isSmall && + this.messaging.publicLivechatGlobal.rule.action === "auto_popup" + ) { + const autoPopupCookie = getCookie("im_livechat_auto_popup"); if (!autoPopupCookie || JSON.parse(autoPopupCookie)) { this.update({ autoOpenChatTimeout: setTimeout( this.openChat, - this.messaging.publicLivechatGlobal.rule.auto_popup_timer * 1000, + this.messaging.publicLivechatGlobal.rule.auto_popup_timer * 1000 ), }); } } if (this.buttonBackgroundColor) { - this.widget.$el.css('background-color', this.buttonBackgroundColor); + this.widget.$el.css("background-color", this.buttonBackgroundColor); } if (this.buttonTextColor) { - this.widget.$el.css('color', this.buttonTextColor); + this.widget.$el.css("color", this.buttonTextColor); } // If website_event_track installed, put the livechat banner above the PWA banner. - const pwaBannerHeight = $('.o_pwa_install_banner').outerHeight(true); + const pwaBannerHeight = $(".o_pwa_install_banner").outerHeight(true); if (pwaBannerHeight) { - this.widget.$el.css('bottom', pwaBannerHeight + 'px'); + this.widget.$el.css("bottom", pwaBannerHeight + "px"); } }, /** @@ -186,7 +213,7 @@ Model({ if (this.isOpeningChat) { return; } - const cookie = getCookie('im_livechat_session'); + const cookie = getCookie("im_livechat_session"); let def; this.update({ isOpeningChat: true }); clearTimeout(this.autoOpenChatTimeout); @@ -195,19 +222,24 @@ Model({ } else { // re-initialize messages cache this.messaging.publicLivechatGlobal.update({ messages: clear() }); - def = this.messaging.rpc({ - route: '/im_livechat/get_session', - params: { - ...this.widget._prepareGetSessionParameters(), - persisted: false, + def = this.messaging.rpc( + { + route: "/im_livechat/get_session", + params: { + ...this.widget._prepareGetSessionParameters(), + persisted: false, + }, }, - }, { silent: true }); + { silent: true } + ); } def.then((livechatData) => { if (!livechatData || !livechatData.operator_pid) { try { this.widget.displayNotification({ - message: this.env._t("No available collaborator, please try again later."), + message: this.env._t( + "No available collaborator, please try again later." + ), sticky: true, }); } catch { @@ -218,7 +250,9 @@ Model({ * lib at the moment because they use bootstrap toast and * we don't want to include boostrap in external lib. */ - console.warn(this.env._t("No available collaborator, please try again later.")); + console.warn( + this.env._t("No available collaborator, please try again later.") + ); } } else { this.messaging.publicLivechatGlobal.update({ @@ -232,11 +266,13 @@ Model({ this.messaging.publicLivechatGlobal.publicLivechat.updateSessionCookie(); }); } - }).then(() => { - this.update({ isOpeningChat: false }); - }).guardedCatch(() => { - this.update({ isOpeningChat: false }); - }); + }) + .then(() => { + this.update({ isOpeningChat: false }); + }) + .guardedCatch(() => { + this.update({ isOpeningChat: false }); + }); }, /** * Resuming the chatbot script if we are currently running one. @@ -250,7 +286,7 @@ Model({ * @override */ _openChatWindowChatbot() { - window.addEventListener('resize', () => { + window.addEventListener("resize", () => { if (this.messaging.publicLivechatGlobal.chatWindow) { this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.scrollToBottom(); } @@ -270,10 +306,15 @@ Model({ * @param {Object} message */ async _sendMessage(message) { - this.messaging.publicLivechatGlobal.publicLivechat.widget._notifyMyselfTyping({ typing: false }); + this.messaging.publicLivechatGlobal.publicLivechat.widget._notifyMyselfTyping({ + typing: false, + }); const messageId = await this.messaging.rpc({ - route: '/mail/chat_post', - params: { uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, message_content: message.content }, + route: "/mail/chat_post", + params: { + uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, + message_content: message.content, + }, }); if (!messageId) { try { @@ -309,18 +350,23 @@ Model({ this.messaging.publicLivechatGlobal.chatbot.currentStep.data ) { if ( - this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_step_type === 'forward_operator' && - this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_operator_found + this.messaging.publicLivechatGlobal.chatbot.currentStep.data + .chatbot_step_type === "forward_operator" && + this.messaging.publicLivechatGlobal.chatbot.currentStep.data + .chatbot_operator_found ) { return; // operator has taken over the conversation, let them speak - } else if (this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_step_type === 'free_input_multi') { + } else if ( + this.messaging.publicLivechatGlobal.chatbot.currentStep.data + .chatbot_step_type === "free_input_multi" + ) { this.messaging.publicLivechatGlobal.chatbot.debouncedAwaitUserInput(); } else if (!this.messaging.publicLivechatGlobal.chatbot.shouldEndScript) { this.messaging.publicLivechatGlobal.chatbot.setIsTyping(); this.messaging.publicLivechatGlobal.chatbot.update({ nextStepTimeout: setTimeout( this.messaging.publicLivechatGlobal.chatbot.triggerNextStep, - this.messaging.publicLivechatGlobal.chatbot.messageDelay, + this.messaging.publicLivechatGlobal.chatbot.messageDelay ), }); } else { @@ -420,7 +466,7 @@ Model({ } return this.env._t("Ask something ..."); }, - default: '', + default: "", }), isOpenChatDebounced: attr({ compute() { @@ -440,9 +486,9 @@ Model({ return _.debounce(this._openChat, 200, true); }, }), - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'livechatButtonView', + inverse: "livechatButtonView", }), serverUrl: attr({ compute() { diff --git a/addons/im_livechat/static/src/public_models/livechat_operator.js b/addons/im_livechat/static/src/public_models/livechat_operator.js index 36425940651..c8d84e91b47 100644 --- a/addons/im_livechat/static/src/public_models/livechat_operator.js +++ b/addons/im_livechat/static/src/public_models/livechat_operator.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { attr, Model } from '@mail/model'; +import { attr, Model } from "@mail/model"; Model({ - name: 'LivechatOperator', + name: "LivechatOperator", fields: { id: attr({ identifying: true, diff --git a/addons/im_livechat/static/src/public_models/messaging.js b/addons/im_livechat/static/src/public_models/messaging.js index fd01900febb..220d20f351b 100644 --- a/addons/im_livechat/static/src/public_models/messaging.js +++ b/addons/im_livechat/static/src/public_models/messaging.js @@ -1,11 +1,11 @@ /** @odoo-module **/ -import { one, Patch } from '@mail/model'; +import { one, Patch } from "@mail/model"; Patch({ - name: 'Messaging', + name: "Messaging", fields: { - publicLivechatGlobal: one('PublicLivechatGlobal', { + publicLivechatGlobal: one("PublicLivechatGlobal", { isCausal: true, }), }, diff --git a/addons/im_livechat/static/src/public_models/public_livechat.js b/addons/im_livechat/static/src/public_models/public_livechat.js index 55aa3aa0080..3e46a4bdff5 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat.js +++ b/addons/im_livechat/static/src/public_models/public_livechat.js @@ -1,14 +1,14 @@ /** @odoo-module **/ -import PublicLivechat from '@im_livechat/legacy/models/public_livechat'; +import PublicLivechat from "@im_livechat/legacy/models/public_livechat"; -import { attr, clear, one, Model } from '@mail/model'; +import { attr, clear, one, Model } from "@mail/model"; -import { unaccent } from 'web.utils'; -import { deleteCookie, setCookie } from 'web.utils.cookies'; +import { unaccent } from "web.utils"; +import { deleteCookie, setCookie } from "web.utils.cookies"; Model({ - name: 'PublicLivechat', + name: "PublicLivechat", lifecycleHooks: { _created() { this.update({ @@ -75,9 +75,9 @@ Model({ return false; }, }), - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'publicLivechat', + inverse: "publicLivechat", }), name: attr({ compute() { @@ -87,7 +87,7 @@ Model({ return this.data.name; }, }), - operator: one('LivechatOperator', { + operator: one("LivechatOperator", { compute() { if (!this.data) { return clear(); @@ -109,7 +109,7 @@ Model({ if (!this.data) { return clear(); } - return this.data.status || ''; + return this.data.status || ""; }, }), // amount of messages that have not yet been read on this chat diff --git a/addons/im_livechat/static/src/public_models/public_livechat_feedback_view.js b/addons/im_livechat/static/src/public_models/public_livechat_feedback_view.js index 16714a3af2e..8a4e15a547a 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_feedback_view.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_feedback_view.js @@ -1,23 +1,23 @@ /** @odoo-module **/ -import Feedback from '@im_livechat/legacy/widgets/feedback/feedback'; +import Feedback from "@im_livechat/legacy/widgets/feedback/feedback"; -import { attr, one, Model } from '@mail/model'; +import { attr, one, Model } from "@mail/model"; Model({ - name: 'PublicLivechatFeedbackView', + name: "PublicLivechatFeedbackView", lifecycleHooks: { _created() { this.update({ widget: new Feedback( this.messaging.publicLivechatGlobal.livechatButtonView.widget, this.messaging, - this.messaging.publicLivechatGlobal.publicLivechat.widget, + this.messaging.publicLivechatGlobal.publicLivechat.widget ), }); this.messaging.publicLivechatGlobal.chatWindow.widget.replaceContentWith(this.widget); - this.widget.on('feedback_sent', null, this._onFeedbackSent); - this.widget.on('send_message', null, this._onSendMessage); + this.widget.on("feedback_sent", null, this._onFeedbackSent); + this.widget.on("send_message", null, this._onSendMessage); }, _willDelete() { this.widget.destroy(); @@ -32,9 +32,9 @@ Model({ }, }, fields: { - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'feedbackView', + inverse: "feedbackView", }), widget: attr(), }, diff --git a/addons/im_livechat/static/src/public_models/public_livechat_global.js b/addons/im_livechat/static/src/public_models/public_livechat_global.js index 21f3a86c090..455bdf680ad 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_global.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_global.js @@ -1,17 +1,17 @@ /** @odoo-module **/ -import { attr, clear, many, one, Model } from '@mail/model'; +import { attr, clear, many, one, Model } from "@mail/model"; -import { qweb } from 'web.core'; -import { Markup } from 'web.utils'; -import {getCookie, setCookie, deleteCookie} from 'web.utils.cookies'; +import { qweb } from "web.core"; +import { Markup } from "web.utils"; +import { getCookie, setCookie, deleteCookie } from "web.utils.cookies"; Model({ - name: 'PublicLivechatGlobal', + name: "PublicLivechatGlobal", lifecycleHooks: { _created() { // History tracking - const page = window.location.href.replace(/^.*\/\/[^/]+/, ''); + const page = window.location.href.replace(/^.*\/\/[^/]+/, ""); const pageHistory = getCookie(this.LIVECHAT_COOKIE_HISTORY); let urlHistory = []; if (pageHistory) { @@ -22,7 +22,12 @@ Model({ while (urlHistory.length > this.HISTORY_LIMIT) { urlHistory.shift(); } - setCookie(this.LIVECHAT_COOKIE_HISTORY, JSON.stringify(urlHistory), 60 * 60 * 24, 'optional'); // 1 day cookie + setCookie( + this.LIVECHAT_COOKIE_HISTORY, + JSON.stringify(urlHistory), + 60 * 60 * 24, + "optional" + ); // 1 day cookie } if (this.isAvailable) { this.willStart(); @@ -31,7 +36,7 @@ Model({ }, recordMethods: { async loadQWebTemplate() { - const templates = await this.messaging.rpc({ route: '/im_livechat/load_templates' }); + const templates = await this.messaging.rpc({ route: "/im_livechat/load_templates" }); for (const template of templates) { qweb.add_template(template); } @@ -42,12 +47,12 @@ Model({ await this._willStartChatbot(); }, async _willStart() { - const strCookie = getCookie('im_livechat_session'); + const strCookie = getCookie("im_livechat_session"); const isSessionCookieAvailable = Boolean(strCookie); - const cookie = JSON.parse(strCookie || '{}'); + const cookie = JSON.parse(strCookie || "{}"); if (cookie.id) { const history = await this.messaging.rpc({ - route: '/mail/chat_history', + route: "/mail/chat_history", params: { uuid: cookie.uuid, limit: 100 }, }); history.reverse(); @@ -60,7 +65,7 @@ Model({ this.update({ history: [], isAvailableForMe: true }); } else { const result = await this.messaging.rpc({ - route: '/im_livechat/init', + route: "/im_livechat/init", params: { channel_id: this.channelId }, }); if (result.available_for_me) { @@ -94,37 +99,40 @@ Model({ } else if (this.history !== null && this.history.length === 0) { this.update({ livechatInit: await this.messaging.rpc({ - route: '/im_livechat/init', + route: "/im_livechat/init", params: { channel_id: this.channelId }, }), }); } else if (this.history !== null && this.history.length !== 0) { - const sessionCookie = getCookie('im_livechat_session'); + const sessionCookie = getCookie("im_livechat_session"); if (sessionCookie) { this.update({ sessionCookie }); } } - if (this.chatbot.state === 'init') { + if (this.chatbot.state === "init") { // we landed on a website page where a channel rule is configured to run a chatbot.script // -> initialize necessary state - if (this.rule.chatbot_welcome_steps && this.rule.chatbot_welcome_steps.length !== 0) { + if ( + this.rule.chatbot_welcome_steps && + this.rule.chatbot_welcome_steps.length !== 0 + ) { this.chatbot.update({ currentStep: { data: this.chatbot.lastWelcomeStep, }, }); } - } else if (this.chatbot.state === 'welcome') { + } else if (this.chatbot.state === "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 // -> initialize necessary state // -> batch welcome message (see '_sendWelcomeChatbotMessage') - deleteCookie('im_livechat_auto_popup'); + deleteCookie("im_livechat_auto_popup"); this.update({ history: clear() }); this.update({ rule: this.livechatInit.rule }); - } else if (this.chatbot.state === 'restore_session') { + } else if (this.chatbot.state === "restore_session") { // we landed on a website page and a chatbot script is currently running // -> restore the user's session (see 'Chatbot/restoreSession') this.chatbot.restoreSession(); @@ -136,7 +144,7 @@ Model({ default: 15, }), LIVECHAT_COOKIE_HISTORY: attr({ - default: 'im_livechat_history', + default: "im_livechat_history", }), RATING_TO_EMOJI: attr({ default: { @@ -150,15 +158,15 @@ Model({ return this.options.channel_id; }, }), - chatbot: one('Chatbot', { + chatbot: one("Chatbot", { default: {}, - inverse: 'publicLivechatGlobalOwner', + inverse: "publicLivechatGlobalOwner", }), - chatWindow: one('PublicLivechatWindow', { - inverse: 'publicLivechatGlobalOwner', + chatWindow: one("PublicLivechatWindow", { + inverse: "publicLivechatGlobalOwner", }), - feedbackView: one('PublicLivechatFeedbackView', { - inverse: 'publicLivechatGlobalOwner', + feedbackView: one("PublicLivechatFeedbackView", { + inverse: "publicLivechatGlobalOwner", }), hasLoadedQWebTemplate: attr({ default: false, @@ -204,7 +212,7 @@ Model({ }, default: false, }), - lastMessage: one('PublicLivechatMessage', { + lastMessage: one("PublicLivechatMessage", { compute() { if (this.messages.length === 0) { return clear(); @@ -212,35 +220,40 @@ Model({ return this.messages[this.messages.length - 1]; }, }), - livechatButtonView: one('LivechatButtonView', { + livechatButtonView: one("LivechatButtonView", { compute() { - if (this.isAvailable && (this.isAvailableForMe || this.isTestChatbot) && this.hasLoadedQWebTemplate && this.env.services.public_livechat_service) { + if ( + this.isAvailable && + (this.isAvailableForMe || this.isTestChatbot) && + this.hasLoadedQWebTemplate && + this.env.services.public_livechat_service + ) { return {}; } return clear(); }, - inverse: 'publicLivechatGlobalOwner', + inverse: "publicLivechatGlobalOwner", }), livechatInit: attr(), - messages: many('PublicLivechatMessage'), - notificationHandler: one('PublicLivechatGlobalNotificationHandler', { - inverse: 'publicLivechatGlobalOwner', + messages: many("PublicLivechatMessage"), + notificationHandler: one("PublicLivechatGlobalNotificationHandler", { + inverse: "publicLivechatGlobalOwner", compute() { if (this.publicLivechat && !this.publicLivechat.isTemporary) { return {}; } return clear(); - } + }, }), options: attr({ default: {}, }), - publicLivechat: one('PublicLivechat', { - inverse: 'publicLivechatGlobalOwner', + publicLivechat: one("PublicLivechat", { + inverse: "publicLivechatGlobalOwner", }), rule: attr(), serverUrl: attr({ - default: '', + default: "", }), sessionCookie: attr(), testChatbotData: attr({ @@ -251,10 +264,14 @@ Model({ return this.options.testChatbotData; }, }), - welcomeMessages: many('PublicLivechatMessage', { + welcomeMessages: many("PublicLivechatMessage", { compute() { return this.messages.filter((message) => { - return message.id && typeof message.id === 'string' && message.id.startsWith('_welcome_'); + return ( + message.id && + typeof message.id === "string" && + message.id.startsWith("_welcome_") + ); }); }, }), diff --git a/addons/im_livechat/static/src/public_models/public_livechat_global_notification_handler.js b/addons/im_livechat/static/src/public_models/public_livechat_global_notification_handler.js index f10727d3a9b..534caed177e 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_global_notification_handler.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_global_notification_handler.js @@ -1,17 +1,19 @@ /** @odoo-module **/ -import { increment, one, Model } from '@mail/model'; +import { increment, one, Model } from "@mail/model"; -import session from 'web.session'; -import utils from 'web.utils'; -import {getCookie} from 'web.utils.cookies'; +import session from "web.session"; +import utils from "web.utils"; +import { getCookie } from "web.utils.cookies"; Model({ - name: 'PublicLivechatGlobalNotificationHandler', + name: "PublicLivechatGlobalNotificationHandler", lifecycleHooks: { _created() { - this.env.services['bus_service'].addChannel(this.messaging.publicLivechatGlobal.publicLivechat.uuid); - this.env.services['bus_service'].addEventListener('notification', this._onNotification); + this.env.services["bus_service"].addChannel( + this.messaging.publicLivechatGlobal.publicLivechat.uuid + ); + this.env.services["bus_service"].addEventListener("notification", this._onNotification); }, }, recordMethods: { @@ -23,43 +25,61 @@ Model({ */ _handleNotification({ payload: notifPayload, type }) { switch (type) { - case 'im_livechat.history_command': { + case "im_livechat.history_command": { if (notifPayload.id !== this.messaging.publicLivechatGlobal.publicLivechat.id) { return; } - const cookie = getCookie(this.messaging.publicLivechatGlobal.LIVECHAT_COOKIE_HISTORY); + const cookie = getCookie( + this.messaging.publicLivechatGlobal.LIVECHAT_COOKIE_HISTORY + ); const history = cookie ? JSON.parse(cookie) : []; - session.rpc('/im_livechat/history', { + session.rpc("/im_livechat/history", { pid: this.messaging.publicLivechatGlobal.publicLivechat.operator.id, channel_uuid: this.messaging.publicLivechatGlobal.publicLivechat.uuid, page_history: history, }); return; } - case 'mail.channel.member/typing_status': { - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { + case "mail.channel.member/typing_status": { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { return; } const channelMemberData = notifPayload; - if (channelMemberData.channel.id !== this.messaging.publicLivechatGlobal.publicLivechat.id) { + if ( + channelMemberData.channel.id !== + this.messaging.publicLivechatGlobal.publicLivechat.id + ) { return; } if (!channelMemberData.persona.partner) { return; } - if (channelMemberData.persona.partner.id === this.messaging.publicLivechatGlobal.livechatButtonView.currentPartnerId) { + if ( + channelMemberData.persona.partner.id === + this.messaging.publicLivechatGlobal.livechatButtonView.currentPartnerId + ) { // ignore typing display of current partner. return; } if (channelMemberData.isTyping) { - this.messaging.publicLivechatGlobal.publicLivechat.widget.registerTyping({ partnerID: channelMemberData.persona.partner.id }); + this.messaging.publicLivechatGlobal.publicLivechat.widget.registerTyping({ + partnerID: channelMemberData.persona.partner.id, + }); } else { - this.messaging.publicLivechatGlobal.publicLivechat.widget.unregisterTyping({ partnerID: channelMemberData.persona.partner.id }); + this.messaging.publicLivechatGlobal.publicLivechat.widget.unregisterTyping({ + partnerID: channelMemberData.persona.partner.id, + }); } return; } - case 'mail.channel/new_message': { - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { + case "mail.channel/new_message": { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { return; } if (notifPayload.id !== this.messaging.publicLivechatGlobal.publicLivechat.id) { @@ -67,26 +87,42 @@ Model({ } const notificationData = notifPayload.message; // If message from notif is already in chatter messages, stop handling - if (this.messaging.publicLivechatGlobal.messages.some(message => message.id === notificationData.id)) { + if ( + this.messaging.publicLivechatGlobal.messages.some( + (message) => message.id === notificationData.id + ) + ) { return; } notificationData.body = utils.Markup(notificationData.body); - this.messaging.publicLivechatGlobal.livechatButtonView.addMessage(notificationData); - if (this.messaging.publicLivechatGlobal.publicLivechat.isFolded || !this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.isAtBottom()) { - this.messaging.publicLivechatGlobal.publicLivechat.update({ unreadCounter: increment() }); + this.messaging.publicLivechatGlobal.livechatButtonView.addMessage( + notificationData + ); + if ( + this.messaging.publicLivechatGlobal.publicLivechat.isFolded || + !this.messaging.publicLivechatGlobal.chatWindow.publicLivechatView.widget.isAtBottom() + ) { + this.messaging.publicLivechatGlobal.publicLivechat.update({ + unreadCounter: increment(), + }); } this.messaging.publicLivechatGlobal.chatWindow.renderMessages(); return; } - case 'mail.record/insert': { + case "mail.record/insert": { const { Message: payload } = notifPayload; if (!payload) { return; } - if (!this.messaging.publicLivechatGlobal.chatWindow || !this.messaging.publicLivechatGlobal.chatWindow.exists()) { + if ( + !this.messaging.publicLivechatGlobal.chatWindow || + !this.messaging.publicLivechatGlobal.chatWindow.exists() + ) { return; } - const message = this.messaging.publicLivechatGlobal.messages.find(message => message.id === payload.id); + const message = this.messaging.publicLivechatGlobal.messages.find( + (message) => message.id === payload.id + ); if (!message) { return; } @@ -108,9 +144,9 @@ Model({ }, }, fields: { - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'notificationHandler', + inverse: "notificationHandler", }), }, }); diff --git a/addons/im_livechat/static/src/public_models/public_livechat_message.js b/addons/im_livechat/static/src/public_models/public_livechat_message.js index 51f0125e202..8e22b436072 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_message.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_message.js @@ -1,14 +1,20 @@ /** @odoo-module **/ -import { attr, clear, Model } from '@mail/model'; +import { attr, clear, Model } from "@mail/model"; -import PublicLivechatMessage from '@im_livechat/legacy/models/public_livechat_message'; +import PublicLivechatMessage from "@im_livechat/legacy/models/public_livechat_message"; Model({ - name: 'PublicLivechatMessage', + name: "PublicLivechatMessage", lifecycleHooks: { _created() { - this.update({ widget: new PublicLivechatMessage(this.messaging.publicLivechatGlobal.livechatButtonView.widget, this.messaging, this.data) }); + this.update({ + widget: new PublicLivechatMessage( + this.messaging.publicLivechatGlobal.livechatButtonView.widget, + this.messaging, + this.data + ), + }); }, _willDelete() { this.widget.destroy(); diff --git a/addons/im_livechat/static/src/public_models/public_livechat_view.js b/addons/im_livechat/static/src/public_models/public_livechat_view.js index 042ba4e03df..23d5418a07c 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_view.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_view.js @@ -1,11 +1,11 @@ /** @odoo-module **/ -import PublicLivechatView from '@im_livechat/legacy/widgets/public_livechat_view/public_livechat_view'; +import PublicLivechatView from "@im_livechat/legacy/widgets/public_livechat_view/public_livechat_view"; -import { attr, one, Model } from '@mail/model'; +import { attr, one, Model } from "@mail/model"; Model({ - name: 'PublicLivechatView', + name: "PublicLivechatView", lifecycleHooks: { _created() { this.update({ @@ -17,9 +17,9 @@ Model({ }, }, fields: { - publicLivechatWindowOwner: one('PublicLivechatWindow', { + publicLivechatWindowOwner: one("PublicLivechatWindow", { identifying: true, - inverse: 'publicLivechatView', + inverse: "publicLivechatView", }), widget: attr(), }, diff --git a/addons/im_livechat/static/src/public_models/public_livechat_window.js b/addons/im_livechat/static/src/public_models/public_livechat_window.js index de15a4881ff..8103cf5e5bf 100644 --- a/addons/im_livechat/static/src/public_models/public_livechat_window.js +++ b/addons/im_livechat/static/src/public_models/public_livechat_window.js @@ -1,18 +1,18 @@ /** @odoo-module **/ -import PublicLivechatWindow from '@im_livechat/legacy/widgets/public_livechat_window/public_livechat_window'; +import PublicLivechatWindow from "@im_livechat/legacy/widgets/public_livechat_window/public_livechat_window"; -import { attr, one, Model } from '@mail/model'; +import { attr, one, Model } from "@mail/model"; Model({ - name: 'PublicLivechatWindow', + name: "PublicLivechatWindow", lifecycleHooks: { _created() { this.update({ widget: new PublicLivechatWindow( this.messaging.publicLivechatGlobal.livechatButtonView.widget, this.messaging, - this.messaging.publicLivechatGlobal.publicLivechat.widget, + this.messaging.publicLivechatGlobal.publicLivechat.widget ), }); }, @@ -22,16 +22,25 @@ Model({ }, recordMethods: { enableInput() { - const $composerTextField = this.widget.$('.o_composer_text_field'); + const $composerTextField = this.widget.$(".o_composer_text_field"); $composerTextField - .prop('disabled', false) - .removeClass('text-center fst-italic bg-200') - .val('') + .prop("disabled", false) + .removeClass("text-center fst-italic bg-200") + .val("") .focus(); - $composerTextField.off('keydown', this.messaging.publicLivechatGlobal.chatbot.onKeydownInput); - if (this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_step_type === 'free_input_multi') { - $composerTextField.on('keydown', this.messaging.publicLivechatGlobal.chatbot.onKeydownInput); + $composerTextField.off( + "keydown", + this.messaging.publicLivechatGlobal.chatbot.onKeydownInput + ); + if ( + this.messaging.publicLivechatGlobal.chatbot.currentStep.data.chatbot_step_type === + "free_input_multi" + ) { + $composerTextField.on( + "keydown", + this.messaging.publicLivechatGlobal.chatbot.onKeydownInput + ); } }, /** @@ -41,9 +50,10 @@ Model({ * @private */ disableInput(disableText) { - this.widget.$('.o_composer_text_field') - .prop('disabled', true) - .addClass('text-center fst-italic bg-200') + this.widget + .$(".o_composer_text_field") + .prop("disabled", true) + .addClass("text-center fst-italic bg-200") .val(disableText); }, renderMessages() { @@ -54,11 +64,18 @@ Model({ } const self = this; - this.widget.$('.o_thread_message:last .o_livechat_chatbot_options li').each(function () { - $(this).on('click', self.messaging.publicLivechatGlobal.livechatButtonView.widget._onChatbotOptionClicked.bind(self.messaging.publicLivechatGlobal.livechatButtonView.widget)); - }); + this.widget + .$(".o_thread_message:last .o_livechat_chatbot_options li") + .each(function () { + $(this).on( + "click", + self.messaging.publicLivechatGlobal.livechatButtonView.widget._onChatbotOptionClicked.bind( + self.messaging.publicLivechatGlobal.livechatButtonView.widget + ) + ); + }); - this.widget.$('.o_livechat_chatbot_main_restart').on('click', (ev) => { + this.widget.$(".o_livechat_chatbot_main_restart").on("click", (ev) => { ev.stopPropagation(); // prevent fold behaviour this.messaging.publicLivechatGlobal.livechatButtonView.onChatbotRestartScript(ev); }); @@ -66,7 +83,11 @@ Model({ if (this.messaging.publicLivechatGlobal.messages.length !== 0) { const lastMessage = this.messaging.publicLivechatGlobal.lastMessage; const stepAnswers = lastMessage.widget.getChatbotStepAnswers(); - if (stepAnswers && stepAnswers.length !== 0 && !lastMessage.widget.getChatbotStepAnswerId()) { + if ( + stepAnswers && + stepAnswers.length !== 0 && + !lastMessage.widget.getChatbotStepAnswerId() + ) { this.disableInput(this.env._t("Select an option above")); } } @@ -81,13 +102,13 @@ Model({ return this.env._t("Say something"); }, }), - publicLivechatGlobalOwner: one('PublicLivechatGlobal', { + publicLivechatGlobalOwner: one("PublicLivechatGlobal", { identifying: true, - inverse: 'chatWindow', + inverse: "chatWindow", }), - publicLivechatView: one('PublicLivechatView', { + publicLivechatView: one("PublicLivechatView", { default: {}, - inverse: 'publicLivechatWindowOwner', + inverse: "publicLivechatWindowOwner", }), widget: attr(), }, diff --git a/addons/im_livechat/static/src/scss/im_livechat_bootstrap.scss b/addons/im_livechat/static/src/scss/im_livechat_bootstrap.scss index 7242f2661f0..740c1a77c4d 100644 --- a/addons/im_livechat/static/src/scss/im_livechat_bootstrap.scss +++ b/addons/im_livechat/static/src/scss/im_livechat_bootstrap.scss @@ -1,35 +1,36 @@ .text-muted { - color: map-get($grays, '600'); + color: map-get($grays, "600"); } .text-start { - text-align: left; + text-align: left; } .text-center { - text-align: center; + text-align: center; } .o_thread_window { - &,* { - box-sizing: border-box; - } - .o_thread_window_header { - height: 35px; - .fa-close { - text-decoration: none; - font-weight: bold; - &:before { - content: "\00d7"; - font-size: initial; - } + &, + * { + box-sizing: border-box; } - > span { - margin: auto 0; + .o_thread_window_header { + height: 35px; + .fa-close { + text-decoration: none; + font-weight: bold; + &:before { + content: "\00d7"; + font-size: initial; + } + } + > span { + margin: auto 0; + } } - } - .o_email_chat_button:after { - content:' \27A4'; - } + .o_email_chat_button:after { + content: " \27A4"; + } } diff --git a/addons/im_livechat/static/src/scss/im_livechat_form.scss b/addons/im_livechat/static/src/scss/im_livechat_form.scss index 8c319f9417d..4be9abeca13 100644 --- a/addons/im_livechat/static/src/scss/im_livechat_form.scss +++ b/addons/im_livechat/static/src/scss/im_livechat_form.scss @@ -13,4 +13,3 @@ margin: 0 5px 0 0; } } - diff --git a/addons/im_livechat/static/src/scss/im_livechat_history.scss b/addons/im_livechat/static/src/scss/im_livechat_history.scss index 0874567bada..5ffab3d0651 100644 --- a/addons/im_livechat/static/src/scss/im_livechat_history.scss +++ b/addons/im_livechat/static/src/scss/im_livechat_history.scss @@ -1,19 +1,19 @@ -.o_history_container{ +.o_history_container { table-layout: fixed; width: 100% !important; > tbody > tr > td { padding: 0px !important; } .o_history_kanban_container { - text-align:center; + text-align: center; .o_history_kanban_sub_container { .o_kanban_ungrouped { flex-flow: column; - max-height:500px; - overflow:auto; - padding:2px 0px; + max-height: 500px; + overflow: auto; + padding: 2px 0px; .rounded-circle { - width:32px; + width: 32px; height: 32px; } .o_kanban_record { @@ -25,7 +25,7 @@ } } .oe_module_vignette { - text-align:left; + text-align: left; } .o_kanban_image { padding-top: 8px; @@ -34,6 +34,5 @@ padding: 8px 8px 0px 64px; } } - } } diff --git a/addons/im_livechat/static/src/services/public_livechat_service.js b/addons/im_livechat/static/src/services/public_livechat_service.js index 1b1c06ba240..4c3f5e2a9b4 100644 --- a/addons/im_livechat/static/src/services/public_livechat_service.js +++ b/addons/im_livechat/static/src/services/public_livechat_service.js @@ -1,17 +1,17 @@ /** @odoo-module **/ -import LivechatButton from '@im_livechat/legacy/widgets/livechat_button'; +import LivechatButton from "@im_livechat/legacy/widgets/livechat_button"; -import rootWidget from 'root.widget'; +import rootWidget from "root.widget"; export const publicLivechatService = { - dependencies: ['messaging'], + dependencies: ["messaging"], async start(env, { messaging: messagingService }) { const messaging = await messagingService.get(); return { mountLivechatButton() { const livechatButton = new LivechatButton(rootWidget, messaging); - livechatButton.appendTo(document.body).catch(error => { + livechatButton.appendTo(document.body).catch((error) => { console.info("Can't load 'LivechatButton' because:", error); }); return livechatButton; diff --git a/addons/im_livechat/static/tests/helpers/mock_server/controllers/main.js b/addons/im_livechat/static/tests/helpers/mock_server/controllers/main.js index 60ec036a2c3..04cdee7d61c 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/controllers/main.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/controllers/main.js @@ -3,19 +3,24 @@ import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; -patch(MockServer.prototype, 'im_livechat/controllers/main', { +patch(MockServer.prototype, "im_livechat/controllers/main", { /** * @override */ async _performRPC(route, args) { - if (route === '/im_livechat/get_session') { + if (route === "/im_livechat/get_session") { const channel_id = args.channel_id; const anonymous_name = args.anonymous_name; const previous_operator_id = args.previous_operator_id; const context = args.context; - return this._mockRouteImLivechatGetSession(channel_id, anonymous_name, previous_operator_id, context); + return this._mockRouteImLivechatGetSession( + channel_id, + anonymous_name, + previous_operator_id, + context + ); } - if (route === '/im_livechat/notify_typing') { + if (route === "/im_livechat/notify_typing") { const uuid = args.uuid; const is_typing = args.is_typing; const context = args.context; @@ -33,10 +38,10 @@ patch(MockServer.prototype, 'im_livechat/controllers/main', { * @param {Object} [context={}] * @returns {Object} */ - _mockRouteImLivechatGetSession(channel_id, anonymous_name, previous_operator_id, context = {}) { + _mockRouteImLivechatGetSession(channel_id, anonymous_name, previous_operator_id, context = {}) { let user_id; let country_id; - if ('mockedUserId' in context) { + if ("mockedUserId" in context) { // can be falsy to simulate not being logged in user_id = context.mockedUserId; } else { @@ -44,18 +49,24 @@ patch(MockServer.prototype, 'im_livechat/controllers/main', { } // don't use the anonymous name if the user is logged in if (user_id) { - const user = this.getRecords('res.users', [['id', '=', user_id]])[0]; + const user = this.getRecords("res.users", [["id", "=", user_id]])[0]; country_id = user.country_id; } else { // simulate geoip const countryCode = context.mockedCountryCode; - const country = this.getRecords('res.country', [['code', '=', countryCode]])[0]; + const country = this.getRecords("res.country", [["code", "=", countryCode]])[0]; if (country) { country_id = country.id; - anonymous_name = anonymous_name + ' (' + country.name + ')'; + anonymous_name = anonymous_name + " (" + country.name + ")"; } } - return this._mockImLivechatChannel_openLivechatMailChannel(channel_id, anonymous_name, previous_operator_id, user_id, country_id); + return this._mockImLivechatChannel_openLivechatMailChannel( + channel_id, + anonymous_name, + previous_operator_id, + user_id, + country_id + ); }, /** * Simulates the `/im_livechat/notify_typing` route. @@ -66,9 +77,12 @@ patch(MockServer.prototype, 'im_livechat/controllers/main', { * @param {Object} [context={}] */ _mockRouteImLivechatNotifyTyping(uuid, is_typing, context = {}) { - const [mailChannel] = this.getRecords('mail.channel', [['uuid', '=', uuid]]); + const [mailChannel] = this.getRecords("mail.channel", [["uuid", "=", uuid]]); const partnerId = context.mockedPartnerId || this.currentPartnerId; - const [memberOfCurrentUser] = this.getRecords('mail.channel.member', [['channel_id', '=', mailChannel.id], ['partner_id', '=', partnerId]]); + const [memberOfCurrentUser] = this.getRecords("mail.channel.member", [ + ["channel_id", "=", mailChannel.id], + ["partner_id", "=", partnerId], + ]); this._mockMailChannelMember_NotifyTyping([memberOfCurrentUser.id], is_typing); }, }); diff --git a/addons/im_livechat/static/tests/helpers/mock_server/models/im_livechat_channel.js b/addons/im_livechat/static/tests/helpers/mock_server/models/im_livechat_channel.js index 11720fc1102..5ddf2e9a3be 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/models/im_livechat_channel.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/models/im_livechat_channel.js @@ -3,7 +3,7 @@ import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; -patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { +patch(MockServer.prototype, "im_livechat/models/im_livechat_channel", { /** * Simulates `_get_available_users` on `im_livechat.channel`. * @@ -12,9 +12,9 @@ patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { * @returns {Object} */ _mockImLivechatChannel_getAvailableUsers(id) { - const livechatChannel = this.getRecords('im_livechat.channel', [['id', '=', id]])[0]; - const users = this.getRecords('res.users', [['id', 'in', livechatChannel.user_ids]]); - return users.filter(user => user.im_status === 'online'); + const livechatChannel = this.getRecords("im_livechat.channel", [["id", "=", id]])[0]; + const users = this.getRecords("res.users", [["id", "in", livechatChannel.user_ids]]); + return users.filter((user) => user.im_status === "online"); }, /** * Simulates `_get_livechat_mail_channel_vals` on `im_livechat.channel`. @@ -23,16 +23,28 @@ patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { * @param {integer} id * @returns {Object} */ - _mockImLivechatChannel_getLivechatMailChannelVals(id, anonymous_name, operator, user_id, country_id) { + _mockImLivechatChannel_getLivechatMailChannelVals( + id, + anonymous_name, + operator, + user_id, + country_id + ) { // partner to add to the mail.channel const operator_partner_id = operator.partner_id; - const membersToAdd = [[0, 0, { - is_pinned: false, - partner_id: operator_partner_id, - }]]; + const membersToAdd = [ + [ + 0, + 0, + { + is_pinned: false, + partner_id: operator_partner_id, + }, + ], + ]; let visitor_user; if (user_id) { - const visitor_user = this.getRecords('res.users', [['id', '=', user_id]])[0]; + const visitor_user = this.getRecords("res.users", [["id", "=", user_id]])[0]; if (visitor_user && visitor_user.active && visitor_user !== operator) { // valid session user (not public) membersToAdd.push([0, 0, { partner_id: visitor_user.partner_id.id }]); @@ -45,14 +57,14 @@ patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { operator.livechat_username ? operator.livechat_username : operator.name, ]; return { - 'channel_member_ids': membersToAdd, - 'livechat_active': true, - 'livechat_operator_id': operator_partner_id, - 'livechat_channel_id': id, - 'anonymous_name': user_id ? false : anonymous_name, - 'country_id': country_id, - 'channel_type': 'livechat', - 'name': membersName.join(' '), + channel_member_ids: membersToAdd, + livechat_active: true, + livechat_operator_id: operator_partner_id, + livechat_channel_id: id, + anonymous_name: user_id ? false : anonymous_name, + country_id: country_id, + channel_type: "livechat", + name: membersName.join(" "), }; }, /** @@ -78,11 +90,17 @@ patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { * @param {integer} [country_id] * @returns {Object} */ - _mockImLivechatChannel_openLivechatMailChannel(id, anonymous_name, previous_operator_id, user_id, country_id) { + _mockImLivechatChannel_openLivechatMailChannel( + id, + anonymous_name, + previous_operator_id, + user_id, + country_id + ) { let operator; if (previous_operator_id) { const availableUsers = this._mockImLivechatChannel_getAvailableUsers(id); - operator = availableUsers.find(user => user.partner_id === previous_operator_id); + operator = availableUsers.find((user) => user.partner_id === previous_operator_id); } if (!operator) { operator = this._mockImLivechatChannel_getRandomOperator(id); @@ -92,8 +110,14 @@ patch(MockServer.prototype, 'im_livechat/models/im_livechat_channel', { return false; } // create the session, and add the link with the given channel - const mailChannelVals = this._mockImLivechatChannel_getLivechatMailChannelVals(id, anonymous_name, operator, user_id, country_id); - const mailChannelId = this.pyEnv['mail.channel'].create(mailChannelVals); + const mailChannelVals = this._mockImLivechatChannel_getLivechatMailChannelVals( + id, + anonymous_name, + operator, + user_id, + country_id + ); + const mailChannelId = this.pyEnv["mail.channel"].create(mailChannelVals); this._mockMailChannel_broadcast([mailChannelId], [operator.partner_id]); return this._mockMailChannelChannelInfo([mailChannelId])[0]; }, diff --git a/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel.js b/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel.js index 87d4977e10b..fa7cc4f3b4f 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel.js @@ -1,26 +1,31 @@ /** @odoo-module **/ -import '@mail/../tests/helpers/mock_server/models/mail_channel'; // ensure mail overrides are applied first +import "@mail/../tests/helpers/mock_server/models/mail_channel"; // ensure mail overrides are applied first import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; -patch(MockServer.prototype, 'im_livechat/models/mail_channel', { +patch(MockServer.prototype, "im_livechat/models/mail_channel", { /** * @override */ _mockMailChannelChannelInfo(ids) { const channelInfos = this._super(...arguments); for (const channelInfo of channelInfos) { - const channel = this.getRecords('mail.channel', [['id', '=', channelInfo.id]])[0]; - channelInfo['channel']['anonymous_name'] = channel.anonymous_name; + const channel = this.getRecords("mail.channel", [["id", "=", channelInfo.id]])[0]; + channelInfo["channel"]["anonymous_name"] = channel.anonymous_name; // add the last message date - if (channel.channel_type === 'livechat') { + if (channel.channel_type === "livechat") { // add the operator id if (channel.livechat_operator_id) { - const operator = this.getRecords('res.partner', [['id', '=', channel.livechat_operator_id]])[0]; + const operator = this.getRecords("res.partner", [ + ["id", "=", channel.livechat_operator_id], + ])[0]; // livechat_username ignored for simplicity - channelInfo.operator_pid = [operator.id, operator.display_name.replace(',', '')]; + channelInfo.operator_pid = [ + operator.id, + operator.display_name.replace(",", ""), + ]; } } } diff --git a/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel_member.js b/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel_member.js index 1f4cc6384dd..23374579c85 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel_member.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/models/mail_channel_member.js @@ -1,37 +1,39 @@ /** @odoo-module **/ -import '@mail/../tests/helpers/mock_server/models/mail_channel_member'; // ensure mail overrides are applied first +import "@mail/../tests/helpers/mock_server/models/mail_channel_member"; // ensure mail overrides are applied first import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; -patch(MockServer.prototype, 'im_livechat/models/mail_channel_member', { +patch(MockServer.prototype, "im_livechat/models/mail_channel_member", { /** * @override */ _mockMailChannelMember_GetPartnerData(ids) { - const [member] = this.getRecords('mail.channel.member', [['id', 'in', ids]]); - const [channel] = this.getRecords('mail.channel', [['id', '=', member.channel_id]]); - const [partner] = this.getRecords('res.partner', [['id', '=', member.partner_id]], { active_test: false }); - if (channel.channel_type === 'livechat') { + const [member] = this.getRecords("mail.channel.member", [["id", "in", ids]]); + const [channel] = this.getRecords("mail.channel", [["id", "=", member.channel_id]]); + const [partner] = this.getRecords("res.partner", [["id", "=", member.partner_id]], { + active_test: false, + }); + if (channel.channel_type === "livechat") { const data = { - 'id': partner.id, - 'is_public': partner.is_public, + id: partner.id, + is_public: partner.is_public, }; if (partner.user_livechat_username) { - data['user_livechat_username'] = partner.user_livechat_username; + data["user_livechat_username"] = partner.user_livechat_username; } else { - data['name'] = partner.name; + data["name"] = partner.name; } if (!partner.is_public) { - const [country] = this.getRecords('res.country', [['id', '=', partner.country_id]]); - data['country'] = country + const [country] = this.getRecords("res.country", [["id", "=", partner.country_id]]); + data["country"] = country ? { - 'code': country.code, - 'id': country.id, - 'name': country.name, - } - : [['clear']]; + code: country.code, + id: country.id, + name: country.name, + } + : [["clear"]]; } return data; } diff --git a/addons/im_livechat/static/tests/helpers/mock_server/models/res_partner.js b/addons/im_livechat/static/tests/helpers/mock_server/models/res_partner.js index 4f3466b721a..d03e239a198 100644 --- a/addons/im_livechat/static/tests/helpers/mock_server/models/res_partner.js +++ b/addons/im_livechat/static/tests/helpers/mock_server/models/res_partner.js @@ -1,24 +1,24 @@ /** @odoo-module **/ -import '@mail/../tests/helpers/mock_server/models/res_partner'; // ensure mail overrides are applied first +import "@mail/../tests/helpers/mock_server/models/res_partner"; // ensure mail overrides are applied first import { patch } from "@web/core/utils/patch"; import { MockServer } from "@web/../tests/helpers/mock_server"; -patch(MockServer.prototype, 'im_livechat/models/res_partner', { +patch(MockServer.prototype, "im_livechat/models/res_partner", { /** * @override */ _mockResPartner_GetChannelsAsMember(ids) { - const partner = this.getRecords('res.partner', [['id', 'in', ids]])[0]; - const members = this.getRecords('mail.channel.member', [['partner_id', '=', partner.id], ['is_pinned', '=', true]]); - const livechats = this.getRecords('mail.channel', [ - ['channel_type', '=', 'livechat'], - ['channel_member_ids', 'in', members.map(member => member.id)], + const partner = this.getRecords("res.partner", [["id", "in", ids]])[0]; + const members = this.getRecords("mail.channel.member", [ + ["partner_id", "=", partner.id], + ["is_pinned", "=", true], ]); - return [ - ...this._super(ids), - ...livechats, - ]; + const livechats = this.getRecords("mail.channel", [ + ["channel_type", "=", "livechat"], + ["channel_member_ids", "in", members.map((member) => member.id)], + ]); + return [...this._super(ids), ...livechats]; }, }); diff --git a/addons/im_livechat/static/tests/helpers/model_definitions_setup.js b/addons/im_livechat/static/tests/helpers/model_definitions_setup.js index 2207dad2a56..b094c0e11d4 100644 --- a/addons/im_livechat/static/tests/helpers/model_definitions_setup.js +++ b/addons/im_livechat/static/tests/helpers/model_definitions_setup.js @@ -1,8 +1,11 @@ /** @odoo-module **/ -import { addModelNamesToFetch, insertModelFields } from '@bus/../tests/helpers/model_definitions_helpers'; +import { + addModelNamesToFetch, + insertModelFields, +} from "@bus/../tests/helpers/model_definitions_helpers"; -addModelNamesToFetch(['im_livechat.channel']); -insertModelFields('res.users.settings', { +addModelNamesToFetch(["im_livechat.channel"]); +insertModelFields("res.users.settings", { is_discuss_sidebar_category_livechat_open: { default: true }, }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js index eb3ba831d03..196430f63a0 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/chat_window_manager_tests.js @@ -1,52 +1,61 @@ /** @odoo-module **/ -import { - afterNextRender, - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { afterNextRender, start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('chat_window_manager', {}, function () { -QUnit.module('chat_window_manager_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("chat_window_manager", {}, function () { + QUnit.module("chat_window_manager_tests.js"); -QUnit.test('closing a chat window with no message from admin side unpins it', async function (assert) { - assert.expect(1); + QUnit.test( + "closing a chat window with no message from admin side unpins it", + async function (assert) { + assert.expect(1); - const pyEnv = await startServer(); - const resPartnerId1 = pyEnv['res.partner'].create({ name: "Demo" }); - pyEnv['res.users'].create({ partner_id: resPartnerId1 }); - const mailChannelId1 = pyEnv['mail.channel'].create( - { - channel_member_ids: [ - [0, 0, { - is_pinned: true, - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: resPartnerId1 }], - ], - channel_type: "livechat", - uuid: 'channel-10-uuid', - }, - ); - const { messaging } = await start(); + const pyEnv = await startServer(); + const resPartnerId1 = pyEnv["res.partner"].create({ name: "Demo" }); + pyEnv["res.users"].create({ partner_id: resPartnerId1 }); + const mailChannelId1 = pyEnv["mail.channel"].create({ + channel_member_ids: [ + [ + 0, + 0, + { + is_pinned: true, + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: resPartnerId1 }], + ], + channel_type: "livechat", + uuid: "channel-10-uuid", + }); + const { messaging } = await start(); - await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click()); - await afterNextRender(() => document.querySelector(`.o_NotificationListView_preview`).click()); - await afterNextRender(() => document.querySelector(`.o_ChatWindowHeaderView_commandClose`).click()); - const channels = await messaging.rpc({ - model: 'mail.channel', - method: 'channel_info', - args: [mailChannelId1], - }, { shadow: true }); - assert.strictEqual( - channels[0].is_pinned, - false, - 'Livechat channel should not be pinned', - ); -}); - -}); -}); + await afterNextRender(() => + document.querySelector(`.o_MessagingMenu_toggler`).click() + ); + await afterNextRender(() => + document.querySelector(`.o_NotificationListView_preview`).click() + ); + await afterNextRender(() => + document.querySelector(`.o_ChatWindowHeaderView_commandClose`).click() + ); + const channels = await messaging.rpc( + { + model: "mail.channel", + method: "channel_info", + args: [mailChannelId1], + }, + { shadow: true } + ); + assert.strictEqual( + channels[0].is_pinned, + false, + "Livechat channel should not be pinned" + ); + } + ); + }); + }); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/composer_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/composer_tests.js index bc4dab99c92..69c35f29ac4 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/composer_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/composer_tests.js @@ -1,50 +1,52 @@ /** @odoo-module **/ -import { start, startServer } from '@mail/../tests/helpers/test_utils'; +import { start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('composer_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("composer_tests.js"); -QUnit.test('livechat: no add attachment button', async function (assert) { - // Attachments are not yet supported in livechat, especially from livechat - // visitor PoV. This may likely change in the future with task-2029065. - assert.expect(2); + QUnit.test("livechat: no add attachment button", async function (assert) { + // Attachments are not yet supported in livechat, especially from livechat + // visitor PoV. This may likely change in the future with task-2029065. + assert.expect(2); - const pyEnv = await startServer(); - const livechatId = pyEnv['mail.channel'].create({ channel_type: 'livechat' }); - const { openDiscuss } = await start({ - discuss: { - context: { active_id: livechatId }, - }, + const pyEnv = await startServer(); + const livechatId = pyEnv["mail.channel"].create({ channel_type: "livechat" }); + const { openDiscuss } = await start({ + discuss: { + context: { active_id: livechatId }, + }, + }); + await openDiscuss(); + assert.containsOnce(document.body, ".o_ComposerView", "should have a composer"); + assert.containsNone( + document.body, + ".o_ComposerView_buttonAttachment", + "composer linked to livechat should not have a 'Add attachment' button" + ); + }); + + QUnit.test( + "livechat: disable attachment upload via drag and drop", + async function (assert) { + assert.expect(2); + + const pyEnv = await startServer(); + const livechatId = pyEnv["mail.channel"].create({ channel_type: "livechat" }); + const { openDiscuss } = await start({ + discuss: { + context: { active_id: livechatId }, + }, + }); + await openDiscuss(); + assert.containsOnce(document.body, ".o_ComposerView", "should have a composer"); + assert.containsNone( + document.body, + ".o_ComposerView_dropZone", + "composer linked to livechat should not have a dropzone" + ); + } + ); }); - await openDiscuss(); - assert.containsOnce(document.body, '.o_ComposerView', "should have a composer"); - assert.containsNone( - document.body, - '.o_ComposerView_buttonAttachment', - "composer linked to livechat should not have a 'Add attachment' button" - ); -}); - -QUnit.test('livechat: disable attachment upload via drag and drop', async function (assert) { - assert.expect(2); - - const pyEnv = await startServer(); - const livechatId = pyEnv['mail.channel'].create({ channel_type: 'livechat' }); - const { openDiscuss } = await start({ - discuss: { - context: { active_id: livechatId }, - }, - }); - await openDiscuss(); - assert.containsOnce(document.body, '.o_ComposerView', "should have a composer"); - assert.containsNone( - document.body, - '.o_ComposerView_dropZone', - "composer linked to livechat should not have a dropzone" - ); -}); - -}); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_item_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_item_tests.js index 9f357bafbe7..1ddc61e9804 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_item_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_item_tests.js @@ -1,77 +1,81 @@ /** @odoo-module **/ -import { - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('discuss_sidebar_category_item_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("discuss_sidebar_category_item_tests.js"); -QUnit.test('livechat - avatar: should have a smiley face avatar for an anonymous livechat item', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - avatar: should have a smiley face avatar for an anonymous livechat item", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - const livechatItem = document.querySelector(` + const livechatItem = document.querySelector(` .o_DiscussSidebarCategoryItem[data-channel-id="${mailChannelId1}"] `); - assert.containsOnce( - livechatItem, - `.o_DiscussSidebarCategoryItem_image`, - "should have an avatar" - ); - assert.strictEqual( - livechatItem.querySelector(`:scope .o_DiscussSidebarCategoryItem_image`).dataset.src, - '/mail/static/src/img/smiley/avatar.jpg', - 'should have the smiley face as the avatar for anonymous users' - ); -}); + assert.containsOnce( + livechatItem, + `.o_DiscussSidebarCategoryItem_image`, + "should have an avatar" + ); + assert.strictEqual( + livechatItem.querySelector(`:scope .o_DiscussSidebarCategoryItem_image`).dataset + .src, + "/mail/static/src/img/smiley/avatar.jpg", + "should have the smiley face as the avatar for anonymous users" + ); + } + ); -QUnit.test('livechat - avatar: should have a partner profile picture for a livechat item linked with a partner', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - avatar: should have a partner profile picture for a livechat item linked with a partner", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const resPartnerId1 = pyEnv['res.partner'].create({ - name: "Jean", - }); - const mailChannelId1 = pyEnv['mail.channel'].create({ - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: resPartnerId1 }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const resPartnerId1 = pyEnv["res.partner"].create({ + name: "Jean", + }); + const mailChannelId1 = pyEnv["mail.channel"].create({ + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: resPartnerId1 }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - const livechatItem = document.querySelector(` + const livechatItem = document.querySelector(` .o_DiscussSidebarCategoryItem[data-channel-id="${mailChannelId1}"] `); - assert.containsOnce( - livechatItem, - `.o_DiscussSidebarCategoryItem_image`, - "should have an avatar" - ); - assert.strictEqual( - livechatItem.querySelector(`:scope .o_DiscussSidebarCategoryItem_image`).dataset.src, - `/web/image/res.partner/${resPartnerId1}/avatar_128`, - 'should have the partner profile picture as the avatar for partners' - ); -}); - -}); + assert.containsOnce( + livechatItem, + `.o_DiscussSidebarCategoryItem_image`, + "should have an avatar" + ); + assert.strictEqual( + livechatItem.querySelector(`:scope .o_DiscussSidebarCategoryItem_image`).dataset + .src, + `/web/image/res.partner/${resPartnerId1}/avatar_128`, + "should have the partner profile picture as the avatar for partners" + ); + } + ); + }); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_tests.js index 7503704b0b7..7e1e8fe17dd 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_sidebar_category_tests.js @@ -1,453 +1,507 @@ /** @odoo-module **/ -import { - afterNextRender, - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { afterNextRender, start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('discuss_sidebar_category_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("discuss_sidebar_category_tests.js"); -QUnit.test('livechat - counter: should not have a counter if the category is unfolded and without unread messages', async function (assert) { - assert.expect(1); + QUnit.test( + "livechat - counter: should not have a counter if the category is unfolded and without unread messages", + async function (assert) { + assert.expect(1); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - document.body, - `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, - "should not have a counter if the category is unfolded and without unread messages", - ); -}); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); + assert.containsNone( + document.body, + `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, + "should not have a counter if the category is unfolded and without unread messages" + ); + } + ); -QUnit.test('livechat - counter: should not have a counter if the category is unfolded and with unread messages', async function (assert) { - assert.expect(1); + QUnit.test( + "livechat - counter: should not have a counter if the category is unfolded and with unread messages", + async function (assert) { + assert.expect(1); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { - message_unread_counter: 10, - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - document.body, - `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, - "should not have a counter if the category is unfolded and with unread messages", - ); -}); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [ + 0, + 0, + { + message_unread_counter: 10, + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); + assert.containsNone( + document.body, + `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, + "should not have a counter if the category is unfolded and with unread messages" + ); + } + ); -QUnit.test('livechat - counter: should not have a counter if category is folded and without unread messages', async function (assert) { - assert.expect(1); + QUnit.test( + "livechat - counter: should not have a counter if category is folded and without unread messages", + async function (assert) { + assert.expect(1); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: false, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: false, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - assert.containsNone( - document.body, - `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, - "should not have a counter if the category is folded and without unread messages" - ); -}); + assert.containsNone( + document.body, + `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`, + "should not have a counter if the category is folded and without unread messages" + ); + } + ); -QUnit.test('livechat - counter: should have correct value of unread threads if category is folded and with unread messages', async function (assert) { - assert.expect(1); + QUnit.test( + "livechat - counter: should have correct value of unread threads if category is folded and with unread messages", + async function (assert) { + assert.expect(1); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { - message_unread_counter: 10, - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: false, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [ + 0, + 0, + { + message_unread_counter: 10, + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: false, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - assert.strictEqual( - document.querySelector(`.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter`).textContent, - "1", - "should have correct value of unread threads if category is folded and with unread messages" - ); -}); + assert.strictEqual( + document.querySelector( + `.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_counter` + ).textContent, + "1", + "should have correct value of unread threads if category is folded and with unread messages" + ); + } + ); -QUnit.test('livechat - states: close manually by clicking the title', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - states: close manually by clicking the title", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: true, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: true, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - // fold the livechat category - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + // fold the livechat category + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); - assert.containsNone( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - "Category livechat should be closed and the content should be invisible" - ); -}); + ` + ) + .click() + ); + assert.containsNone( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "Category livechat should be closed and the content should be invisible" + ); + } + ); -QUnit.test('livechat - states: open manually by clicking the title', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - states: open manually by clicking the title", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: false, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: false, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - assert.containsNone( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); + assert.containsNone( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - // open the livechat category - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + // open the livechat category + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - "Category livechat should be open and the content should be visible" - ); -}); + ` + ) + .click() + ); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "Category livechat should be open and the content should be visible" + ); + } + ); -QUnit.test('livechat - states: close should update the value on the server', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - states: close should update the value on the server", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: true, - }); - const currentUserId = pyEnv.currentUserId; - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: true, + }); + const currentUserId = pyEnv.currentUserId; + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - const initalSettings = await messaging.rpc({ - model: 'res.users.settings', - method: '_find_or_create_for_user', - args: [[currentUserId]], - }); - assert.strictEqual( - initalSettings.is_discuss_sidebar_category_livechat_open, - true, - "the value in server side should be true" - ); + const initalSettings = await messaging.rpc({ + model: "res.users.settings", + method: "_find_or_create_for_user", + args: [[currentUserId]], + }); + assert.strictEqual( + initalSettings.is_discuss_sidebar_category_livechat_open, + true, + "the value in server side should be true" + ); - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); - const newSettings = await messaging.rpc({ - model: 'res.users.settings', - method: '_find_or_create_for_user', - args: [[currentUserId]], - }); - assert.strictEqual( - newSettings.is_discuss_sidebar_category_livechat_open, - false, - "the value in server side should be false" - ); -}); + ` + ) + .click() + ); + const newSettings = await messaging.rpc({ + model: "res.users.settings", + method: "_find_or_create_for_user", + args: [[currentUserId]], + }); + assert.strictEqual( + newSettings.is_discuss_sidebar_category_livechat_open, + false, + "the value in server side should be false" + ); + } + ); -QUnit.test('livechat - states: open should update the value on the server', async function (assert) { - assert.expect(2); + QUnit.test( + "livechat - states: open should update the value on the server", + async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: false, - }); - const currentUserId = pyEnv.currentUserId; - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: false, + }); + const currentUserId = pyEnv.currentUserId; + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - const initalSettings = await messaging.rpc({ - model: 'res.users.settings', - method: '_find_or_create_for_user', - args: [[currentUserId]], - }); - assert.strictEqual( - initalSettings.is_discuss_sidebar_category_livechat_open, - false, - "the value in server side should be false" - ); + const initalSettings = await messaging.rpc({ + model: "res.users.settings", + method: "_find_or_create_for_user", + args: [[currentUserId]], + }); + assert.strictEqual( + initalSettings.is_discuss_sidebar_category_livechat_open, + false, + "the value in server side should be false" + ); - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); - const newSettings = await messaging.rpc({ - model: 'res.users.settings', - method: '_find_or_create_for_user', - args: [[currentUserId]], - }); - assert.strictEqual( - newSettings.is_discuss_sidebar_category_livechat_open, - true, - "the value in server side should be true" - ); -}); + ` + ) + .click() + ); + const newSettings = await messaging.rpc({ + model: "res.users.settings", + method: "_find_or_create_for_user", + args: [[currentUserId]], + }); + assert.strictEqual( + newSettings.is_discuss_sidebar_category_livechat_open, + true, + "the value in server side should be true" + ); + } + ); -QUnit.test('livechat - states: close from the bus', async function (assert) { - assert.expect(2); + QUnit.test("livechat - states: close from the bus", async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const resUsersSettingsId1 = pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: true, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const resUsersSettingsId1 = pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: true, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - await afterNextRender(() => { - pyEnv['bus.bus']._sendone(pyEnv.currentPartner, 'mail.record/insert', { - 'res.users.settings': { - 'id': resUsersSettingsId1, - 'is_discuss_sidebar_category_livechat_open': false, - }, + await afterNextRender(() => { + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { + "res.users.settings": { + id: resUsersSettingsId1, + is_discuss_sidebar_category_livechat_open: false, + }, + }); + }); + assert.containsNone( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "Category livechat should be closed and the content should be invisible" + ); }); - }); - assert.containsNone( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - "Category livechat should be closed and the content should be invisible" - ); -}); -QUnit.test('livechat - states: open from the bus', async function (assert) { - assert.expect(2); + QUnit.test("livechat - states: open from the bus", async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const resUsersSettingsId1 = pyEnv['res.users.settings'].create({ - user_id: pyEnv.currentUserId, - is_discuss_sidebar_category_livechat_open: false, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const resUsersSettingsId1 = pyEnv["res.users.settings"].create({ + user_id: pyEnv.currentUserId, + is_discuss_sidebar_category_livechat_open: false, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - assert.containsNone( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); + assert.containsNone( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - await afterNextRender(() => { - pyEnv['bus.bus']._sendone(pyEnv.currentPartner, 'mail.record/insert', { - 'res.users.settings': { - id: resUsersSettingsId1, - 'is_discuss_sidebar_category_livechat_open': true, - }, + await afterNextRender(() => { + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { + "res.users.settings": { + id: resUsersSettingsId1, + is_discuss_sidebar_category_livechat_open: true, + }, + }); + }); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "Category livechat should be open and the content should be visible" + ); }); - }); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - "Category livechat should be open and the content should be visible" - ); -}); + QUnit.test( + "livechat - states: category item should be invisible if the category is closed", + async function (assert) { + assert.expect(2); -QUnit.test('livechat - states: category item should be invisible if the category is closed', async function (assert) { - assert.expect(2); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); - - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); + ` + ) + .click() + ); - assert.containsNone( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - "inactive item should be invisible if the category is folded" - ); -}); + assert.containsNone( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "inactive item should be invisible if the category is folded" + ); + } + ); -QUnit.test('livechat - states: the active category item should be visble even if the category is closed', async function (assert) { - assert.expect(3); + QUnit.test( + "livechat - states: the active category item should be visble even if the category is closed", + async function (assert) { + assert.expect(3); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` - ); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); - const livechat = document.querySelector(`.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`); - await afterNextRender(() => { - livechat.click(); - }); - assert.ok(livechat.classList.contains('o-active')); + const livechat = document.querySelector( + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]` + ); + await afterNextRender(() => { + livechat.click(); + }); + assert.ok(livechat.classList.contains("o-active")); - await afterNextRender(() => - document.querySelector(`.o_DiscussSidebarCategory[data-category-local-id="${ - messaging.discuss.categoryLivechat.localId}"] + await afterNextRender(() => + document + .querySelector( + `.o_DiscussSidebarCategory[data-category-local-id="${messaging.discuss.categoryLivechat.localId}"] .o_DiscussSidebarCategory_title - `).click() - ); + ` + ) + .click() + ); - assert.containsOnce( - document.body, - `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, - 'the active livechat item should remain open even if the category is folded' - ); -}); - -}); + assert.containsOnce( + document.body, + `.o_DiscussSidebarCategory_item[data-channel-id="${mailChannelId1}"]`, + "the active livechat item should remain open even if the category is folded" + ); + } + ); + }); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_tests.js index 37dbc38dca2..0c48864604a 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/discuss_tests.js @@ -5,431 +5,449 @@ import { nextAnimationFrame, start, startServer, -} from '@mail/../tests/helpers/test_utils'; +} from "@mail/../tests/helpers/test_utils"; -import { datetime_to_str } from 'web.time'; +import { datetime_to_str } from "web.time"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('discuss_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("discuss_tests.js"); -QUnit.test('livechat in the sidebar: basic rendering', async function (assert) { - assert.expect(5); + QUnit.test("livechat in the sidebar: basic rendering", async function (assert) { + assert.expect(5); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); - assert.containsOnce(document.body, '.o_DiscussView_sidebar', - "should have a sidebar section" - ); - const groupLivechat = document.querySelector('.o_DiscussSidebarView_categoryLivechat'); - assert.ok(groupLivechat, - "should have a channel group livechat" - ); - const titleText = groupLivechat.querySelector('.o_DiscussSidebarCategory_titleText'); - assert.strictEqual( - titleText.textContent.trim(), - "Livechat", - "should have a channel group named 'Livechat'" - ); - const livechat = groupLivechat.querySelector(` + assert.containsOnce( + document.body, + ".o_DiscussView_sidebar", + "should have a sidebar section" + ); + const groupLivechat = document.querySelector(".o_DiscussSidebarView_categoryLivechat"); + assert.ok(groupLivechat, "should have a channel group livechat"); + const titleText = groupLivechat.querySelector(".o_DiscussSidebarCategory_titleText"); + assert.strictEqual( + titleText.textContent.trim(), + "Livechat", + "should have a channel group named 'Livechat'" + ); + const livechat = groupLivechat.querySelector(` .o_DiscussSidebarCategoryItem[data-channel-id="${mailChannelId1}"] `); - assert.ok( - livechat, - "should have a livechat in sidebar" - ); - assert.strictEqual( - livechat.textContent, - "Visitor 11", - "should have 'Visitor 11' as livechat name" - ); -}); - -QUnit.test('livechat in the sidebar: existing user with country', async function (assert) { - assert.expect(3); - - const pyEnv = await startServer(); - const resCountryId1 = pyEnv['res.country'].create({ - code: 'be', - name: "Belgium", - }); - const resPartnerId1 = pyEnv['res.partner'].create({ - country_id: resCountryId1, - name: "Jean", - }); - pyEnv['mail.channel'].create({ - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: resPartnerId1 }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); - - assert.containsOnce( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should have a channel group livechat in the side bar" - ); - const livechat = document.querySelector('.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem'); - assert.ok( - livechat, - "should have a livechat in sidebar" - ); - assert.strictEqual( - livechat.textContent, - "Jean (Belgium)", - "should have user name and country as livechat name" - ); -}); - -QUnit.test('do not add livechat in the sidebar on visitor opening his chat', async function (assert) { - assert.expect(2); - - const pyEnv = await startServer(); - pyEnv['res.users'].write([pyEnv.currentUserId], { im_status: 'online' }); - const imLivechatChannelId1 = pyEnv['im_livechat.channel'].create({ - user_ids: [pyEnv.currentUserId], - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); - - assert.containsNone( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should not have any livechat in the sidebar initially" - ); - - // simulate livechat visitor opening his chat - await messaging.rpc({ - route: '/im_livechat/get_session', - params: { - context: { - mockedUserId: false, - }, - channel_id: imLivechatChannelId1, - }, - }); - await nextAnimationFrame(); - assert.containsNone( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should still not have any livechat in the sidebar after visitor opened his chat" - ); -}); - -QUnit.test('do not add livechat in the sidebar on visitor typing', async function (assert) { - assert.expect(2); - - const pyEnv = await startServer(); - pyEnv['res.users'].write([pyEnv.currentUserId], { im_status: 'online' }); - const imLivechatChannelId1 = pyEnv['im_livechat.channel'].create({ - user_ids: [pyEnv.currentUserId], - }); - const mailChannelId1 = pyEnv['mail.channel'].create({ - channel_member_ids: [ - [0, 0, { - is_pinned: false, - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_channel_id: imLivechatChannelId1, - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); - - assert.containsNone( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should not have any livechat in the sidebar initially" - ); - - // simulate livechat visitor typing - const channel = pyEnv['mail.channel'].searchRead([['id', '=', mailChannelId1]])[0]; - await messaging.rpc({ - route: '/im_livechat/notify_typing', - params: { - context: { - mockedPartnerId: pyEnv.publicPartnerId, - }, - is_typing: true, - uuid: channel.uuid, - }, - }); - await nextAnimationFrame(); - assert.containsNone( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should still not have any livechat in the sidebar after visitor started typing" - ); -}); - -QUnit.test('add livechat in the sidebar on visitor sending first message', async function (assert) { - assert.expect(4); - - const pyEnv = await startServer(); - pyEnv['res.users'].write([pyEnv.currentUserId], { im_status: 'online' }); - const resCountryId1 = pyEnv['res.country'].create({ - code: 'be', - name: "Belgium", - }); - const imLivechatChannelId1 = pyEnv['im_livechat.channel'].create({ - user_ids: [pyEnv.currentUserId], - }); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor (Belgium)", - channel_member_ids: [ - [0, 0, { - is_pinned: false, - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - country_id: resCountryId1, - livechat_channel_id: imLivechatChannelId1, - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { messaging, openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should not have any livechat in the sidebar initially" - ); - - // simulate livechat visitor sending a message - const channel = pyEnv['mail.channel'].searchRead([['id', '=', mailChannelId1]])[0]; - await afterNextRender(async () => messaging.rpc({ - route: '/mail/chat_post', - params: { - context: { - mockedUserId: false, - }, - uuid: channel.uuid, - message_content: "new message", - }, - })); - assert.containsOnce( - document.body, - '.o_DiscussSidebarView_categoryLivechat', - "should have a channel group livechat in the side bar after receiving first message" - ); - assert.containsOnce( - document.body, - '.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem', - "should have a livechat in the sidebar after receiving first message" - ); - assert.strictEqual( - document.querySelector('.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem .o_DiscussSidebarCategoryItem_name').textContent, - "Visitor (Belgium)", - "should have visitor name and country as livechat name" - ); -}); - -QUnit.test('livechats are sorted by last activity time in the sidebar: most recent at the top', async function (assert) { - assert.expect(6); - - const pyEnv = await startServer(); - const [mailChannelId1, mailChannelId2] = pyEnv['mail.channel'].create([ - { - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { - last_interest_dt: datetime_to_str(new Date(2021, 0, 1)), - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }, - { - anonymous_name: "Visitor 12", - channel_member_ids: [ - [0, 0, { - last_interest_dt: datetime_to_str(new Date(2021, 0, 2)), - partner_id: pyEnv.currentPartnerId, - }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }, - ]); - const { openDiscuss } = await start(); - await openDiscuss(); - const initialLivechats = document.querySelectorAll('.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_item'); - assert.strictEqual( - initialLivechats.length, - 2, - "should have 2 livechat items" - ); - assert.strictEqual( - Number(initialLivechats[0].dataset.channelId), - mailChannelId2, - "first livechat should be the one with the more recent last activity time" - ); - assert.strictEqual( - Number(initialLivechats[1].dataset.channelId), - mailChannelId1, - "second livechat should be the one with the less recent last activity time" - ); - - // post a new message on the last channel - await afterNextRender(() => initialLivechats[1].click()); - await afterNextRender(() => document.execCommand('insertText', false, "Blabla")); - await afterNextRender(() => document.querySelector('.o_ComposerView_buttonSend').click()); - - const newLivechats = document.querySelectorAll('.o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_item'); - assert.strictEqual( - newLivechats.length, - 2, - "should have 2 livechat items" - ); - assert.strictEqual( - Number(newLivechats[0].dataset.channelId), - mailChannelId1, - "first livechat should be the one with the more recent last activity time" - ); - assert.strictEqual( - Number(newLivechats[1].dataset.channelId), - mailChannelId2, - "second livechat should be the one with the less recent last activity time" - ); -}); - -QUnit.test('invite button should be present on livechat', async function (assert) { - assert.expect(1); - - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create( - { - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }, - ); - const { openDiscuss } = await start({ - discuss: { - params: { - default_active_id: `mail.channel_${mailChannelId1}`, - }, - }, - }); - await openDiscuss(); - assert.containsOnce( - document.body, - '.o_ThreadViewTopbar_inviteButton', - "Invite button should be visible in top bar when livechat is active thread" - ); -}); - -QUnit.test('call buttons should not be present on livechat', async function (assert) { - assert.expect(1); - - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create( - { - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - }, - ); - const { openDiscuss } = await start({ - discuss: { - params: { - default_active_id: `mail.channel_${mailChannelId1}`, - }, - }, - }); - await openDiscuss(); - assert.containsNone( - document.body, - '.o_ThreadViewTopbar_callButton', - "Call buttons should not be visible in top bar when livechat is active thread" - ); -}); - -QUnit.test('reaction button should not be present on livechat', async function (assert) { - assert.expect(1); - - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - channel_partner_ids: [pyEnv.currentPartnerId, pyEnv.publicPartnerId], - }); - const { click, insertText, openDiscuss } = await start({ - discuss: { - params: { - default_active_id: `mail.channel_${mailChannelId1}`, - }, - }, - }); - await openDiscuss(); - await insertText('.o_ComposerTextInputView_textarea', "Test"); - await click('.o_ComposerView_buttonSend'); - await click('.o_MessageView'); - assert.containsNone( - document.body, - '.o_MessageActionView_actionReaction', - "should not have action to add a reaction" - ); -}); - -QUnit.test('reply button should not be present on livechat', async function (assert) { - assert.expect(1); - - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, - channel_partner_ids: [pyEnv.currentPartnerId, pyEnv.publicPartnerId], - }); - const { click, insertText, openDiscuss } = await start({ - discuss: { - params: { - default_active_id: `mail.channel_${mailChannelId1}`, - }, - }, - }); - await openDiscuss(); - await insertText('.o_ComposerTextInputView_textarea', "Test"); - await click('.o_ComposerView_buttonSend'); - await click('.o_MessageView'); - assert.containsNone( - document.body, - '.o_MessageActionView_actionReplyTo', - "should not have reply action" - ); -}); - -}); + assert.ok(livechat, "should have a livechat in sidebar"); + assert.strictEqual( + livechat.textContent, + "Visitor 11", + "should have 'Visitor 11' as livechat name" + ); + }); + + QUnit.test("livechat in the sidebar: existing user with country", async function (assert) { + assert.expect(3); + + const pyEnv = await startServer(); + const resCountryId1 = pyEnv["res.country"].create({ + code: "be", + name: "Belgium", + }); + const resPartnerId1 = pyEnv["res.partner"].create({ + country_id: resCountryId1, + name: "Jean", + }); + pyEnv["mail.channel"].create({ + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: resPartnerId1 }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + await openDiscuss(); + + assert.containsOnce( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should have a channel group livechat in the side bar" + ); + const livechat = document.querySelector( + ".o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem" + ); + assert.ok(livechat, "should have a livechat in sidebar"); + assert.strictEqual( + livechat.textContent, + "Jean (Belgium)", + "should have user name and country as livechat name" + ); + }); + + QUnit.test( + "do not add livechat in the sidebar on visitor opening his chat", + async function (assert) { + assert.expect(2); + + const pyEnv = await startServer(); + pyEnv["res.users"].write([pyEnv.currentUserId], { im_status: "online" }); + const imLivechatChannelId1 = pyEnv["im_livechat.channel"].create({ + user_ids: [pyEnv.currentUserId], + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); + + assert.containsNone( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should not have any livechat in the sidebar initially" + ); + + // simulate livechat visitor opening his chat + await messaging.rpc({ + route: "/im_livechat/get_session", + params: { + context: { + mockedUserId: false, + }, + channel_id: imLivechatChannelId1, + }, + }); + await nextAnimationFrame(); + assert.containsNone( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should still not have any livechat in the sidebar after visitor opened his chat" + ); + } + ); + + QUnit.test("do not add livechat in the sidebar on visitor typing", async function (assert) { + assert.expect(2); + + const pyEnv = await startServer(); + pyEnv["res.users"].write([pyEnv.currentUserId], { im_status: "online" }); + const imLivechatChannelId1 = pyEnv["im_livechat.channel"].create({ + user_ids: [pyEnv.currentUserId], + }); + const mailChannelId1 = pyEnv["mail.channel"].create({ + channel_member_ids: [ + [ + 0, + 0, + { + is_pinned: false, + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_channel_id: imLivechatChannelId1, + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); + + assert.containsNone( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should not have any livechat in the sidebar initially" + ); + + // simulate livechat visitor typing + const channel = pyEnv["mail.channel"].searchRead([["id", "=", mailChannelId1]])[0]; + await messaging.rpc({ + route: "/im_livechat/notify_typing", + params: { + context: { + mockedPartnerId: pyEnv.publicPartnerId, + }, + is_typing: true, + uuid: channel.uuid, + }, + }); + await nextAnimationFrame(); + assert.containsNone( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should still not have any livechat in the sidebar after visitor started typing" + ); + }); + + QUnit.test( + "add livechat in the sidebar on visitor sending first message", + async function (assert) { + assert.expect(4); + + const pyEnv = await startServer(); + pyEnv["res.users"].write([pyEnv.currentUserId], { im_status: "online" }); + const resCountryId1 = pyEnv["res.country"].create({ + code: "be", + name: "Belgium", + }); + const imLivechatChannelId1 = pyEnv["im_livechat.channel"].create({ + user_ids: [pyEnv.currentUserId], + }); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor (Belgium)", + channel_member_ids: [ + [ + 0, + 0, + { + is_pinned: false, + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + country_id: resCountryId1, + livechat_channel_id: imLivechatChannelId1, + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start(); + await openDiscuss(); + assert.containsNone( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should not have any livechat in the sidebar initially" + ); + + // simulate livechat visitor sending a message + const channel = pyEnv["mail.channel"].searchRead([["id", "=", mailChannelId1]])[0]; + await afterNextRender(async () => + messaging.rpc({ + route: "/mail/chat_post", + params: { + context: { + mockedUserId: false, + }, + uuid: channel.uuid, + message_content: "new message", + }, + }) + ); + assert.containsOnce( + document.body, + ".o_DiscussSidebarView_categoryLivechat", + "should have a channel group livechat in the side bar after receiving first message" + ); + assert.containsOnce( + document.body, + ".o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem", + "should have a livechat in the sidebar after receiving first message" + ); + assert.strictEqual( + document.querySelector( + ".o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategoryItem .o_DiscussSidebarCategoryItem_name" + ).textContent, + "Visitor (Belgium)", + "should have visitor name and country as livechat name" + ); + } + ); + + QUnit.test( + "livechats are sorted by last activity time in the sidebar: most recent at the top", + async function (assert) { + assert.expect(6); + + const pyEnv = await startServer(); + const [mailChannelId1, mailChannelId2] = pyEnv["mail.channel"].create([ + { + anonymous_name: "Visitor 11", + channel_member_ids: [ + [ + 0, + 0, + { + last_interest_dt: datetime_to_str(new Date(2021, 0, 1)), + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }, + { + anonymous_name: "Visitor 12", + channel_member_ids: [ + [ + 0, + 0, + { + last_interest_dt: datetime_to_str(new Date(2021, 0, 2)), + partner_id: pyEnv.currentPartnerId, + }, + ], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }, + ]); + const { openDiscuss } = await start(); + await openDiscuss(); + const initialLivechats = document.querySelectorAll( + ".o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_item" + ); + assert.strictEqual(initialLivechats.length, 2, "should have 2 livechat items"); + assert.strictEqual( + Number(initialLivechats[0].dataset.channelId), + mailChannelId2, + "first livechat should be the one with the more recent last activity time" + ); + assert.strictEqual( + Number(initialLivechats[1].dataset.channelId), + mailChannelId1, + "second livechat should be the one with the less recent last activity time" + ); + + // post a new message on the last channel + await afterNextRender(() => initialLivechats[1].click()); + await afterNextRender(() => document.execCommand("insertText", false, "Blabla")); + await afterNextRender(() => + document.querySelector(".o_ComposerView_buttonSend").click() + ); + + const newLivechats = document.querySelectorAll( + ".o_DiscussSidebarView_categoryLivechat .o_DiscussSidebarCategory_item" + ); + assert.strictEqual(newLivechats.length, 2, "should have 2 livechat items"); + assert.strictEqual( + Number(newLivechats[0].dataset.channelId), + mailChannelId1, + "first livechat should be the one with the more recent last activity time" + ); + assert.strictEqual( + Number(newLivechats[1].dataset.channelId), + mailChannelId2, + "second livechat should be the one with the less recent last activity time" + ); + } + ); + + QUnit.test("invite button should be present on livechat", async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start({ + discuss: { + params: { + default_active_id: `mail.channel_${mailChannelId1}`, + }, + }, + }); + await openDiscuss(); + assert.containsOnce( + document.body, + ".o_ThreadViewTopbar_inviteButton", + "Invite button should be visible in top bar when livechat is active thread" + ); + }); + + QUnit.test("call buttons should not be present on livechat", async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start({ + discuss: { + params: { + default_active_id: `mail.channel_${mailChannelId1}`, + }, + }, + }); + await openDiscuss(); + assert.containsNone( + document.body, + ".o_ThreadViewTopbar_callButton", + "Call buttons should not be visible in top bar when livechat is active thread" + ); + }); + + QUnit.test("reaction button should not be present on livechat", async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + channel_partner_ids: [pyEnv.currentPartnerId, pyEnv.publicPartnerId], + }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + params: { + default_active_id: `mail.channel_${mailChannelId1}`, + }, + }, + }); + await openDiscuss(); + await insertText(".o_ComposerTextInputView_textarea", "Test"); + await click(".o_ComposerView_buttonSend"); + await click(".o_MessageView"); + assert.containsNone( + document.body, + ".o_MessageActionView_actionReaction", + "should not have action to add a reaction" + ); + }); + + QUnit.test("reply button should not be present on livechat", async function (assert) { + assert.expect(1); + + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + channel_partner_ids: [pyEnv.currentPartnerId, pyEnv.publicPartnerId], + }); + const { click, insertText, openDiscuss } = await start({ + discuss: { + params: { + default_active_id: `mail.channel_${mailChannelId1}`, + }, + }, + }); + await openDiscuss(); + await insertText(".o_ComposerTextInputView_textarea", "Test"); + await click(".o_ComposerView_buttonSend"); + await click(".o_MessageView"); + assert.containsNone( + document.body, + ".o_MessageActionView_actionReplyTo", + "should not have reply action" + ); + }); + }); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/messaging_menu_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/messaging_menu_tests.js index 934d3d6bd48..e37433c3bc8 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/messaging_menu_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/messaging_menu_tests.js @@ -1,71 +1,62 @@ /** @odoo-module **/ -import { - afterNextRender, - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { afterNextRender, start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('messaging_menu_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("messaging_menu_tests.js"); -QUnit.test('livechats should be in "chat" filter', async function (assert) { - assert.expect(7); + QUnit.test('livechats should be in "chat" filter', async function (assert) { + assert.expect(7); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + await start(); + assert.containsOnce(document.body, ".o_MessagingMenu", "should have messaging menu"); + + await afterNextRender(() => document.querySelector(".o_MessagingMenu_toggler").click()); + assert.containsOnce( + document.body, + '.o_MessagingMenuTabView[data-tab-id="all"]', + "should have a tab/filter 'all' in messaging menu" + ); + assert.containsOnce( + document.body, + '.o_MessagingMenuTabView[data-tab-id="chat"]', + "should have a tab/filter 'chat' in messaging menu" + ); + assert.hasClass( + document.querySelector('.o_MessagingMenuTabView[data-tab-id="all"]'), + "o-active", + "tab/filter 'all' of messaging menu should be active initially" + ); + assert.containsOnce( + document.body, + `.o_ChannelPreviewView[data-channel-id="${mailChannelId1}"]`, + "livechat should be listed in 'all' tab/filter of messaging menu" + ); + + await afterNextRender(() => + document.querySelector('.o_MessagingMenuTabView[data-tab-id="chat"]').click() + ); + assert.hasClass( + document.querySelector('.o_MessagingMenuTabView[data-tab-id="chat"]'), + "o-active", + "tab/filter 'chat' of messaging menu should become active after click" + ); + assert.containsOnce( + document.body, + `.o_ChannelPreviewView[data-channel-id="${mailChannelId1}"]`, + "livechat should be listed in 'chat' tab/filter of messaging menu" + ); + }); }); - await start(); - assert.containsOnce( - document.body, - '.o_MessagingMenu', - "should have messaging menu" - ); - - await afterNextRender(() => document.querySelector('.o_MessagingMenu_toggler').click()); - assert.containsOnce( - document.body, - '.o_MessagingMenuTabView[data-tab-id="all"]', - "should have a tab/filter 'all' in messaging menu" - ); - assert.containsOnce( - document.body, - '.o_MessagingMenuTabView[data-tab-id="chat"]', - "should have a tab/filter 'chat' in messaging menu" - ); - assert.hasClass( - document.querySelector('.o_MessagingMenuTabView[data-tab-id="all"]'), - 'o-active', - "tab/filter 'all' of messaging menu should be active initially" - ); - assert.containsOnce( - document.body, - `.o_ChannelPreviewView[data-channel-id="${mailChannelId1}"]`, - "livechat should be listed in 'all' tab/filter of messaging menu" - ); - - await afterNextRender(() => - document.querySelector('.o_MessagingMenuTabView[data-tab-id="chat"]').click() - ); - assert.hasClass( - document.querySelector('.o_MessagingMenuTabView[data-tab-id="chat"]'), - 'o-active', - "tab/filter 'chat' of messaging menu should become active after click" - ); - assert.containsOnce( - document.body, - `.o_ChannelPreviewView[data-channel-id="${mailChannelId1}"]`, - "livechat should be listed in 'chat' tab/filter of messaging menu" - ); -}); - -}); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_icon_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_icon_tests.js index e8eceae772a..ffcf76ff8d0 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_icon_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_icon_tests.js @@ -1,68 +1,65 @@ /** @odoo-module **/ -import { - afterNextRender, - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { afterNextRender, start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('thread_icon_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("thread_icon_tests.js"); -QUnit.test('livechat: public website visitor is typing', async function (assert) { - assert.expect(4); + QUnit.test("livechat: public website visitor is typing", async function (assert) { + assert.expect(4); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 20", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 20", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start({ + discuss: { + context: { active_id: mailChannelId1 }, + }, + }); + await openDiscuss(); + assert.containsOnce( + document.body, + ".o_ThreadViewTopbar .o_ThreadIconView", + "should have thread icon" + ); + assert.containsOnce( + document.body, + ".o_ThreadIconView .fa.fa-comments", + "should have default livechat icon" + ); + + const mailChannel1 = pyEnv["mail.channel"].searchRead([["id", "=", mailChannelId1]])[0]; + // simulate receive typing notification from livechat visitor "is typing" + await afterNextRender(() => + messaging.rpc({ + route: "/im_livechat/notify_typing", + params: { + context: { + mockedPartnerId: pyEnv.publicPartnerId, + }, + is_typing: true, + uuid: mailChannel1.uuid, + }, + }) + ); + assert.containsOnce( + document.body, + ".o_ThreadIconView_typing", + "should have thread icon with visitor currently typing" + ); + assert.strictEqual( + document.querySelector(".o_ThreadIconView_typing").title, + "Visitor 20 is typing...", + "title of icon should tell visitor is currently typing" + ); + }); }); - const { messaging, openDiscuss } = await start({ - discuss: { - context: { active_id: mailChannelId1 }, - }, - }); - await openDiscuss(); - assert.containsOnce( - document.body, - '.o_ThreadViewTopbar .o_ThreadIconView', - "should have thread icon" - ); - assert.containsOnce( - document.body, - '.o_ThreadIconView .fa.fa-comments', - "should have default livechat icon" - ); - - const mailChannel1 = pyEnv['mail.channel'].searchRead([['id', '=', mailChannelId1]])[0]; - // simulate receive typing notification from livechat visitor "is typing" - await afterNextRender(() => messaging.rpc({ - route: '/im_livechat/notify_typing', - params: { - context: { - mockedPartnerId: pyEnv.publicPartnerId, - }, - is_typing: true, - uuid: mailChannel1.uuid, - }, - })); - assert.containsOnce( - document.body, - '.o_ThreadIconView_typing', - "should have thread icon with visitor currently typing" - ); - assert.strictEqual( - document.querySelector('.o_ThreadIconView_typing').title, - "Visitor 20 is typing...", - "title of icon should tell visitor is currently typing" - ); -}); - -}); }); diff --git a/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_textual_typing_status_tests.js b/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_textual_typing_status_tests.js index c507a5f950d..6cee4c6ec49 100644 --- a/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_textual_typing_status_tests.js +++ b/addons/im_livechat/static/tests/qunit_suite_tests/components/thread_textual_typing_status_tests.js @@ -1,59 +1,56 @@ /** @odoo-module **/ -import { - afterNextRender, - start, - startServer, -} from '@mail/../tests/helpers/test_utils'; +import { afterNextRender, start, startServer } from "@mail/../tests/helpers/test_utils"; -QUnit.module('im_livechat', {}, function () { -QUnit.module('components', {}, function () { -QUnit.module('thread_textual_typing_status_tests.js'); +QUnit.module("im_livechat", {}, function () { + QUnit.module("components", {}, function () { + QUnit.module("thread_textual_typing_status_tests.js"); -QUnit.test('receive visitor typing status "is typing"', async function (assert) { - assert.expect(2); + QUnit.test('receive visitor typing status "is typing"', async function (assert) { + assert.expect(2); - const pyEnv = await startServer(); - const mailChannelId1 = pyEnv['mail.channel'].create({ - anonymous_name: "Visitor 20", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: 'livechat', - livechat_operator_id: pyEnv.currentPartnerId, + const pyEnv = await startServer(); + const mailChannelId1 = pyEnv["mail.channel"].create({ + anonymous_name: "Visitor 20", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { messaging, openDiscuss } = await start({ + discuss: { + context: { active_id: mailChannelId1 }, + }, + }); + await openDiscuss(); + + assert.strictEqual( + document.querySelector(".o_ThreadTextualTypingStatusView").textContent, + "", + "Should display no one is currently typing" + ); + + const mailChannel1 = pyEnv["mail.channel"].searchRead([["id", "=", mailChannelId1]])[0]; + // simulate receive typing notification from livechat visitor "is typing" + await afterNextRender(() => + messaging.rpc({ + route: "/im_livechat/notify_typing", + params: { + context: { + mockedPartnerId: pyEnv.publicPartnerId, + }, + is_typing: true, + uuid: mailChannel1.uuid, + }, + }) + ); + assert.strictEqual( + document.querySelector(".o_ThreadTextualTypingStatusView").textContent, + "Visitor 20 is typing...", + "Should display that visitor is typing" + ); + }); }); - const { messaging, openDiscuss } = await start({ - discuss: { - context: { active_id: mailChannelId1 }, - }, - }); - await openDiscuss(); - - assert.strictEqual( - document.querySelector('.o_ThreadTextualTypingStatusView').textContent, - "", - "Should display no one is currently typing" - ); - - const mailChannel1 = pyEnv['mail.channel'].searchRead([['id', '=', mailChannelId1]])[0]; - // simulate receive typing notification from livechat visitor "is typing" - await afterNextRender(() => messaging.rpc({ - route: '/im_livechat/notify_typing', - params: { - context: { - mockedPartnerId: pyEnv.publicPartnerId, - }, - is_typing: true, - uuid: mailChannel1.uuid, - }, - })); - assert.strictEqual( - document.querySelector('.o_ThreadTextualTypingStatusView').textContent, - "Visitor 20 is typing...", - "Should display that visitor is typing" - ); -}); - -}); }); diff --git a/addons/im_livechat/static/tests/tours/im_livechat_channel_creation_tour.js b/addons/im_livechat/static/tests/tours/im_livechat_channel_creation_tour.js index 7030571cd65..fb279700a0a 100644 --- a/addons/im_livechat/static/tests/tours/im_livechat_channel_creation_tour.js +++ b/addons/im_livechat/static/tests/tours/im_livechat_channel_creation_tour.js @@ -12,21 +12,26 @@ const requestChatSteps = [ }, ]; -registry.category("web_tour.tours").add("im_livechat_request_chat", { test: true, steps: requestChatSteps}); +registry + .category("web_tour.tours") + .add("im_livechat_request_chat", { test: true, steps: requestChatSteps }); -registry.category("web_tour.tours").add("im_livechat_request_chat_and_send_message", { test: true, steps: [ - ...requestChatSteps, - { - trigger: ".o_composer_text_field", - run: "text Hello, I need help please !", - }, - { - trigger: '.o_composer_text_field', - run() { - $(".o_composer_text_field").trigger($.Event("keydown", { which: 13 })); +registry.category("web_tour.tours").add("im_livechat_request_chat_and_send_message", { + test: true, + steps: [ + ...requestChatSteps, + { + trigger: ".o_composer_text_field", + run: "text Hello, I need help please !", }, - }, - { - trigger: ".o_thread_message:contains('Hello, I need help')", - }, -]}); + { + trigger: ".o_composer_text_field", + run() { + $(".o_composer_text_field").trigger($.Event("keydown", { which: 13 })); + }, + }, + { + trigger: ".o_thread_message:contains('Hello, I need help')", + }, + ], +}); diff --git a/addons/im_livechat/static/tests/tours/im_livechat_chatbot_steps_sequence_tour.js b/addons/im_livechat/static/tests/tours/im_livechat_chatbot_steps_sequence_tour.js index 928dc786b67..74f7a29fbad 100644 --- a/addons/im_livechat/static/tests/tours/im_livechat_chatbot_steps_sequence_tour.js +++ b/addons/im_livechat/static/tests/tours/im_livechat_chatbot_steps_sequence_tour.js @@ -3,122 +3,163 @@ import { registry } from "@web/core/registry"; import { stepUtils } from "@web_tour/js/tour_step_utils"; -const commonSteps = [stepUtils.showAppsMenuItem(), { - trigger: '.o_app[data-menu-xmlid="im_livechat.menu_livechat_root"]', -}, { - trigger: 'button[data-menu-xmlid="im_livechat.livechat_config"]', -}, { - trigger: 'a[data-menu-xmlid="im_livechat.chatbot_config"]', -}, { - trigger: '.o_list_button_add', -}, { - trigger: 'input[id="title"]', - run: 'text Test Chatbot Sequence' -}, { - trigger: 'div[name="script_step_ids"] .o_field_x2many_list_row_add a' -}, { - trigger: 'textarea#message', - run: 'text Step 1' -}, { - trigger: 'button:contains("Save & New")' -}, { - trigger: 'tr:contains("Step 1")', - in_modal: false, - run: () => {} -}, { - trigger: 'textarea#message', - run: 'text Step 2' -}, { - trigger: 'button:contains("Save & New")' -}, { - trigger: 'tr:contains("Step 2")', - in_modal: false, - run: () => {} -}, { - trigger: 'textarea#message', - run: 'text Step 3' -}]; - +const commonSteps = [ + stepUtils.showAppsMenuItem(), + { + trigger: '.o_app[data-menu-xmlid="im_livechat.menu_livechat_root"]', + }, + { + trigger: 'button[data-menu-xmlid="im_livechat.livechat_config"]', + }, + { + trigger: 'a[data-menu-xmlid="im_livechat.chatbot_config"]', + }, + { + trigger: ".o_list_button_add", + }, + { + trigger: 'input[id="title"]', + run: "text Test Chatbot Sequence", + }, + { + trigger: 'div[name="script_step_ids"] .o_field_x2many_list_row_add a', + }, + { + trigger: "textarea#message", + run: "text Step 1", + }, + { + trigger: 'button:contains("Save & New")', + }, + { + trigger: 'tr:contains("Step 1")', + in_modal: false, + run: () => {}, + }, + { + trigger: "textarea#message", + run: "text Step 2", + }, + { + trigger: 'button:contains("Save & New")', + }, + { + trigger: 'tr:contains("Step 2")', + in_modal: false, + run: () => {}, + }, + { + trigger: "textarea#message", + run: "text Step 3", + }, +]; /** * Simply create a few steps in order to check the sequences. */ -registry.category("web_tour.tours").add('im_livechat_chatbot_steps_sequence_tour', { +registry.category("web_tour.tours").add("im_livechat_chatbot_steps_sequence_tour", { test: true, - url: '/web', + url: "/web", steps: [ - ...commonSteps, { - trigger: 'button:contains("Save & Close")' -}, { - trigger: 'body.o_web_client:not(.modal-open)', - run() {}, -}, ...stepUtils.discardForm() -]}); + ...commonSteps, + { + trigger: 'button:contains("Save & Close")', + }, + { + trigger: "body.o_web_client:not(.modal-open)", + run() {}, + }, + ...stepUtils.discardForm(), + ], +}); /** * Same as above, with an extra drag&drop at the end. */ -registry.category("web_tour.tours").add('im_livechat_chatbot_steps_sequence_with_move_tour', { +registry.category("web_tour.tours").add("im_livechat_chatbot_steps_sequence_with_move_tour", { test: true, - url: '/web', + url: "/web", steps: [ - ...commonSteps, { - trigger: 'button:contains("Save & New")' -}, { - trigger: 'tr:contains("Step 3")', - in_modal: false, - run: () => {} -}, { - trigger: 'textarea#message', - run: 'text Step 4' -}, { - trigger: 'button:contains("Save & New")' -}, { - trigger: 'tr:contains("Step 4")', - in_modal: false, - run: () => {} -}, { - trigger: 'textarea#message', - run: 'text Step 5' -}, { - trigger: 'button:contains("Save & Close")' -}, { - trigger: 'body.o_web_client:not(.modal-open)', - run: () => {} -}, { - trigger: 'tr:contains("Step 5") .o_row_handle', - run: () => { - // move 'step 5' between 'step 1' and 'step 2' - const from = document.querySelector('div[name="script_step_ids"] tr:nth-child(5) .o_row_handle'); - const fromPosition = from.getBoundingClientRect(); - fromPosition.x += from.offsetWidth / 2; - fromPosition.y += from.offsetHeight / 2; + ...commonSteps, + { + trigger: 'button:contains("Save & New")', + }, + { + trigger: 'tr:contains("Step 3")', + in_modal: false, + run: () => {}, + }, + { + trigger: "textarea#message", + run: "text Step 4", + }, + { + trigger: 'button:contains("Save & New")', + }, + { + trigger: 'tr:contains("Step 4")', + in_modal: false, + run: () => {}, + }, + { + trigger: "textarea#message", + run: "text Step 5", + }, + { + trigger: 'button:contains("Save & Close")', + }, + { + trigger: "body.o_web_client:not(.modal-open)", + run: () => {}, + }, + { + trigger: 'tr:contains("Step 5") .o_row_handle', + run: () => { + // move 'step 5' between 'step 1' and 'step 2' + const from = document.querySelector( + 'div[name="script_step_ids"] tr:nth-child(5) .o_row_handle' + ); + const fromPosition = from.getBoundingClientRect(); + fromPosition.x += from.offsetWidth / 2; + fromPosition.y += from.offsetHeight / 2; - const to = document.querySelector('div[name="script_step_ids"] tr:nth-child(2) .o_row_handle'); - from.dispatchEvent(new Event("mouseenter", { bubbles: true })); - from.dispatchEvent(new MouseEvent("mousedown", { - bubbles: true, - which: 1, - button: 0, - clientX: fromPosition.x, - clientY: fromPosition.y})); - from.dispatchEvent(new Event("mousemove", { bubbles: true })); - to.dispatchEvent(new Event("mouseenter", { bubbles: true })); - from.dispatchEvent(new Event("mouseup", { bubbles: true })); - } -}, { - trigger: 'div[name="script_step_ids"] .o_field_x2many_list_row_add a' -}, { - trigger: 'textarea#message', - run: 'text Step 6' -}, { - trigger: 'button:contains("Save & Close")' -}, { - trigger: 'body.o_web_client:not(.modal-open)', - run: () => {} -}, { - trigger: 'tr:contains("Step 6")', - in_modal: false, - run: () => {} -}, ...stepUtils.discardForm(), -]}); + const to = document.querySelector( + 'div[name="script_step_ids"] tr:nth-child(2) .o_row_handle' + ); + from.dispatchEvent(new Event("mouseenter", { bubbles: true })); + from.dispatchEvent( + new MouseEvent("mousedown", { + bubbles: true, + which: 1, + button: 0, + clientX: fromPosition.x, + clientY: fromPosition.y, + }) + ); + from.dispatchEvent(new Event("mousemove", { bubbles: true })); + to.dispatchEvent(new Event("mouseenter", { bubbles: true })); + from.dispatchEvent(new Event("mouseup", { bubbles: true })); + }, + }, + { + trigger: 'div[name="script_step_ids"] .o_field_x2many_list_row_add a', + }, + { + trigger: "textarea#message", + run: "text Step 6", + }, + { + trigger: 'button:contains("Save & Close")', + }, + { + trigger: "body.o_web_client:not(.modal-open)", + run: () => {}, + }, + { + trigger: 'tr:contains("Step 6")', + in_modal: false, + run: () => {}, + }, + ...stepUtils.discardForm(), + ], +}); diff --git a/addons/web/tooling/_eslintignore b/addons/web/tooling/_eslintignore index bb635cd404a..8e149e0d268 100644 --- a/addons/web/tooling/_eslintignore +++ b/addons/web/tooling/_eslintignore @@ -152,6 +152,10 @@ addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js !addons/mail/ !addons/mail/**/* +# Whitelist im_livechat +!addons/im_livechat/ +!addons/im_livechat/**/* + # Whitelist point_of_sale !addons/point_of_sale/ !addons/point_of_sale/**/* @@ -195,7 +199,7 @@ addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js !addons/pos_six/**/* !addons/pos_stripe !addons/pos_stripe/**/* - + # Whitelist enterprise pos modules !l10n_de_pos_cert !l10n_de_pos_cert/**/* @@ -210,4 +214,4 @@ addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js !pos_restaurant_iot !pos_restaurant_iot/**/* !pos_settle_due -!pos_settle_due/**/* \ No newline at end of file +!pos_settle_due/**/*