diff --git a/addons/mail/static/src/js/models/threads/dm_chat.js b/addons/mail/static/src/js/models/threads/dm_chat.js index c0ba9c527b0..78cc01a7044 100644 --- a/addons/mail/static/src/js/models/threads/dm_chat.js +++ b/addons/mail/static/src/js/models/threads/dm_chat.js @@ -101,6 +101,19 @@ var DMChat = TwoUserChannel.extend(ChannelSeenMixin, { getStatus: function () { return this.call('mail_service', 'getImStatus', { partnerID: this._directPartnerID }); }, + + /** + * @param {Object} data + * @param {string} data.outOfOfficeMessage + * @param {string} data.outOfOfficeDateEnd + */ + updateOutOfOfficeInfo: function (data) { + this._outOfOfficeMessage = data.outOfOfficeMessage; + this._outOfOfficeDateEnd = data.outOfOfficeDateEnd; + this.call('mail_service', 'getMailBus').trigger('updated_out_of_office', { + threadID: this.getID(), + }); + } }); return DMChat; diff --git a/addons/mail/static/src/js/services/mail_status_manager.js b/addons/mail/static/src/js/services/mail_status_manager.js index 3addaf65349..6f9b996f231 100644 --- a/addons/mail/static/src/js/services/mail_status_manager.js +++ b/addons/mail/static/src/js/services/mail_status_manager.js @@ -54,13 +54,45 @@ MailManager.include({ updateImStatus: function (statusList) { var updatedIDs = []; var self = this; + var dmChat; + var toUpdateOutOfOfficeChatIDs = []; _.each(statusList, function (status) { if (self._imStatus[status.id] === status.im_status) { return; } + if ( + status.im_status.indexOf('leave') !== -1 || + ( + self._imStatus[status.id] && + self._imStatus[status.id].indexOf('leave') !== -1 + ) + ) { + dmChat = self.getDMChatFromPartnerID(status.id); + if (dmChat) { + toUpdateOutOfOfficeChatIDs.push(dmChat.getID()); + } + } updatedIDs.push(status.id); self._imStatus[status.id] = status.im_status; }); + if (!_.isEmpty(toUpdateOutOfOfficeChatIDs)) { + this._rpc({ + model: 'mail.channel', + method: 'channel_info', + args: [toUpdateOutOfOfficeChatIDs], + }).then(function (channelsInfo) { + _.each(channelsInfo, function (channelInfo) { + dmChat = self.getChannel(channelInfo.id); + if (!dmChat) { + return; + } + dmChat.updateOutOfOfficeInfo({ + outOfOfficeMessage: channelInfo.direct_partner[0].out_of_office_message, + outOfOfficeDateEnd: channelInfo.direct_partner[0].out_of_office_date_end, + }); + }); + }); + } if (! _.isEmpty(updatedIDs)) { this._mailBus.trigger('updated_im_status', updatedIDs); // useful for thread window header this._renderImStatus(updatedIDs); diff --git a/addons/mail/static/src/js/services/mail_window_manager.js b/addons/mail/static/src/js/services/mail_window_manager.js index 3f7ce1aed3d..fdb1b667714 100644 --- a/addons/mail/static/src/js/services/mail_window_manager.js +++ b/addons/mail/static/src/js/services/mail_window_manager.js @@ -341,6 +341,7 @@ MailManager.include({ .on('is_thread_bottom_visible', this, this._onIsThreadBottomVisible) .on('unsubscribe_from_channel', this, this._onUnsubscribeFromChannel) .on('updated_im_status', this, this._onUpdatedImStatus) + .on('updated_out_of_office', this, this._onUpdatedOutOfOffice) .on('update_thread_unread_counter', this, this._onUpdateThreadUnreadCounter); core.bus.on('resize', this, _.debounce(this._repositionThreadWindows.bind(this), 100)); @@ -691,6 +692,18 @@ MailManager.include({ threadWindow.renderHeader(); }); }, + /** + * @private + * @param {Object} data + * @param {integer} data.threadID + */ + _onUpdatedOutOfOffice: function (data) { + var threadWindow = this._getThreadWindow(data.threadID); + if (!threadWindow) { + return; + } + threadWindow.renderOutOfOffice(); + }, /** * Called when a thread has its unread counter that has changed. * The unread counter on the thread windows should be updated. diff --git a/addons/mail/static/src/js/thread_windows/thread_window.js b/addons/mail/static/src/js/thread_windows/thread_window.js index e5496e0bc3c..9f7c1f00bb5 100644 --- a/addons/mail/static/src/js/thread_windows/thread_window.js +++ b/addons/mail/static/src/js/thread_windows/thread_window.js @@ -6,6 +6,7 @@ var BasicComposer = require('mail.composer.Basic'); var core = require('web.core'); +var QWeb = core.qweb; var _t = core._t; /** @@ -153,6 +154,23 @@ var ThreadWindow = AbstractThreadWindow.extend({ removePassive: function () { this._passive = false; }, + renderOutOfOffice: function () { + var $outOfOffice = this.$('.o_out_of_office'); + if (!this.getOutOfOfficeInfo() && !this.getOutOfOfficeMessage()) { + if ($outOfOffice.length) { + $outOfOffice.remove(); + } + return; + } + var $newOutOfOffice = $(QWeb.render('mail.thread_window.OutOfOffice', { + widget: this, + })); + if ($outOfOffice.length) { + $outOfOffice.replaceWith($newOutOfOffice); + } else { + $newOutOfOffice.insertAfter(this.$('.o_thread_window_header')); + } + }, /** * Update this thread window * diff --git a/addons/mail/static/src/xml/thread_window.xml b/addons/mail/static/src/xml/thread_window.xml index 76a130d1ba2..a9e2131cbdb 100644 --- a/addons/mail/static/src/xml/thread_window.xml +++ b/addons/mail/static/src/xml/thread_window.xml @@ -6,13 +6,7 @@ --> -
-
-
- - Read more -
-
+
To: @@ -20,6 +14,17 @@ + +
+
+
+ + Read more +
+
+ diff --git a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js index 5a0bc62f880..0445c344649 100644 --- a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js @@ -695,6 +695,119 @@ QUnit.test('no out-of-office status in thread window', function (assert) { parent.destroy(); }); +QUnit.test('auto-update out-of-office info on im_status change', function (assert) { + var done = assert.async(); + assert.expect(5); + + var imStatusDefs = [$.Deferred(), $.Deferred()]; + var channelInfoDefs = [$.Deferred(), $.Deferred()]; + var timeoutMock = mailTestUtils.patchMailTimeouts(); + var step = 0; + + this.data = { + 'mail.message': { + fields: {}, + records: [], + }, + initMessaging: { + channel_slots: { + channel_channel: [{ + id: 1, + name: "DM", + channel_type: "chat", + message_unread_counter: 0, + direct_partner: [{ + id: 666, + name: 'DemoUser1', + im_status: 'online', + }], + }], + }, + }, + }; + + var parent = this.createParent({ + data: this.data, + services: this.services, + mockRPC: function (route, args) { + if (route === '/longpolling/im_status') { + step++; + if (step === 1) { + imStatusDefs[0].resolve(); + return $.when([ + { + id: 666, + im_status: 'leave', + }, + ]); + } else if (step === 2) { + imStatusDefs[1].resolve(); + return $.when([ + { + id: 666, + im_status: 'online', + }, + ]); + } + } + if (args.method === 'channel_info') { + if (step === 1) { + channelInfoDefs[0].resolve(); + return $.when([{ + id: 1, + direct_partner: [{ + out_of_office_message: "Leave me alone", + out_of_office_date_end: false, + }], + }]); + } + else if (step === 2) { + channelInfoDefs[1].resolve(); + return $.when([{ + id: 1, + direct_partner: [{ + out_of_office_message: false, + out_of_office_date_end: false, + }], + }]); + } + } + return this._super.apply(this, arguments); + }, + }); + + // detach channel 1, so that it opens corresponding thread window. + parent.call('mail_service', 'getChannel', 1).detach(); + + assert.containsNone($, '.o_out_of_office', + "should contain no out of office section on chat window initially"); + + timeoutMock.addTime(51*1000); // wait for next im status fetch + + $.when(imStatusDefs[0], channelInfoDefs[0]).then(function () { + assert.containsOnce($, '.o_out_of_office', + "should contain out of office section on chat window"); + assert.containsOnce($, '.o_out_of_office > .o_out_of_office_text', + "should contain out of office text on chat window"); + assert.ok( + $('.o_out_of_office > .o_out_of_office_text') + .text() + .replace(/\s/g, "") + .indexOf("Leavemealone") !== -1, + "should contain out of office text on chat window"); + timeoutMock.addTime(51*1000); // wait for next im status fetch + + $.when(imStatusDefs[1], channelInfoDefs[1]).then(function () { + assert.containsNone($, '.o_out_of_office', + "should no longer contain out of office section on chat window"); + + timeoutMock.runPendingTimeouts(); + parent.destroy(); + done(); + }); + }); +}); + }); }); });