summaryrefslogtreecommitdiff
path: root/addons/sms/static
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2019-06-20 09:55:30 +0000
committerThibault Delavallée <tde@odoo.com>2019-07-12 14:54:11 +0000
commit423cf93eb32df363c16ccabab2fddaea384ceac7 (patch)
treea1920e9d1dae14b7661cf59c75fe04cf46b683d6 /addons/sms/static
parent45555bdd1fddb988bfa54ff54f1bc1887d0dc1df (diff)
[IMP] sms: add UX elements to use SMS notifications
Purpose of this commit is to allow users to have a feedback on SMS notifications status in chatter. This commit contains notably * an update of systray widget that now handles SMS failures. Those are displayed in another item of the systray and redirect to documents having an SMS failure; * an update of chatter widgets to support SMS notifications in messages. Failed notifications appear in red and allow to use the SMS resend wizard; Mail message model gains a new has_sms_error computed and searchable field allowing to filter on messages having failed SMS notifications. Mail thread model gains a new message_has_sms_error computed and searchable field, based on the one on mail.message. It allows to filter on records with failed SMS messages directly from the systray. That way clicking on the systray entry redirects to the right records. Related to task 1922163 Linked to PR #33510 Co-Authored-By: Thibault Delavallee <tde@odoo.com> Co-Authored-By: Pierre Rousseau <pro@odoo.com>
Diffstat (limited to 'addons/sms/static')
-rw-r--r--addons/sms/static/src/js/mail_failure.js29
-rw-r--r--addons/sms/static/src/js/message.js73
-rw-r--r--addons/sms/static/src/js/sms_notification_manager.js64
-rw-r--r--addons/sms/static/src/js/systray_messaging_menu.js80
-rw-r--r--addons/sms/static/src/js/thread_widget.js89
-rw-r--r--addons/sms/static/src/scss/thread.scss5
-rw-r--r--addons/sms/static/src/xml/sms_widget.xml6
-rw-r--r--addons/sms/static/src/xml/thread.xml26
8 files changed, 366 insertions, 6 deletions
diff --git a/addons/sms/static/src/js/mail_failure.js b/addons/sms/static/src/js/mail_failure.js
new file mode 100644
index 00000000000..0acb8cad76a
--- /dev/null
+++ b/addons/sms/static/src/js/mail_failure.js
@@ -0,0 +1,29 @@
+odoo.define('sms.model.MailFailure', function (require) {
+'use strict';
+
+var MailFailure = require('mail.model.MailFailure');
+var core = require('web.core');
+var _t = core._t;
+
+MailFailure.include({
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ getPreview: function () {
+ var preview = this._super.apply(this, arguments);
+ if (this._failureType === 'sms') {
+ _.extend(preview, {
+ body: _t('An error occurred when sending SMS'),
+ id: 'sms_failure',
+ });
+ }
+ return preview;
+ },
+});
+
+});
diff --git a/addons/sms/static/src/js/message.js b/addons/sms/static/src/js/message.js
new file mode 100644
index 00000000000..f800563fd72
--- /dev/null
+++ b/addons/sms/static/src/js/message.js
@@ -0,0 +1,73 @@
+odoo.define('sms.model.Message', function (require) {
+"use strict";
+
+var Message = require('mail.model.Message');
+
+Message.include({
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * Retrieves the list of SMS
+ *
+ * @returns {Array} Array of Array(smsID, recipientName, smsStatus)
+ */
+ getSmsIds: function () {
+ return this._smsIds;
+ },
+ /**
+ * Retrieves the SMS status
+ *
+ * @return {string}
+ */
+ getSmsStatus: function () {
+ var self = this;
+ this._smsStatus = 'sent';
+ _.each(this._smsIds, function (sms) {
+ if (sms[2] === 'bounce' || sms[2] === 'exception') {
+ self._smsStatus = 'error';
+ }
+ });
+ return this._smsStatus;
+ },
+ /**
+ * Does the message contains at least one SMS failure
+ *
+ * @returns {boolean}
+ */
+ isError: function () {
+ return this.getSmsStatus() === 'error';
+ },
+ /**
+ * Update the status of a SMS
+ *
+ * @param {integer} smsID ID of the SMS to update
+ * @param {string} smsStatus New status of the SMS
+ */
+ setSmsStatus: function (smsID, smsStatus) {
+ var self = this;
+ var sms = _.find(self._smsIds, function (sms) {
+ return sms[0] === smsID;
+ });
+ sms[2] = smsStatus;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @private
+ */
+ _setInitialData: function (data) {
+ this._super.apply(this, arguments);
+ this._smsIds = data.sms_ids;
+ if (this._smsStatus === false) {
+ this._smsStatus = 'sent';
+ }
+ },
+});
+});
diff --git a/addons/sms/static/src/js/sms_notification_manager.js b/addons/sms/static/src/js/sms_notification_manager.js
new file mode 100644
index 00000000000..7d93d96fe51
--- /dev/null
+++ b/addons/sms/static/src/js/sms_notification_manager.js
@@ -0,0 +1,64 @@
+odoo.define('sms.NotificationManager', function (require) {
+"use strict";
+
+var MailManager = require('mail.Manager');
+var MailFailure = require('mail.model.MailFailure');
+
+MailManager.include({
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @param {Object} data structure depending on the type
+ * @param {integer} data.id
+ */
+ _handlePartnerNotification: function (data) {
+ if (data.type === 'sms_update') {
+ this._handleSMSUpdateNotification(data);
+ } else {
+ this._super.apply(this, arguments);
+ }
+ },
+ /**
+ * Updates message in thread when there's an update in a SMS letter
+ *
+ * @private
+ * @param {Object} datas
+ * @param {Object[]} datas.elements list of SMS failure data
+ * @param {string} datas.elements[].message_id ID of related message that
+ * has a sms failure.
+ */
+ _handleSMSUpdateNotification: function (datas) {
+ var self = this;
+ _.each(datas.elements, function (data) {
+ var isNewFailure = data.sms_status === 'error';
+ var matchedFailure = _.find(self._mailFailures, function (failure) {
+ return failure.getMessageID() === data.message_id;
+ });
+
+ if (matchedFailure) {
+ var index = _.findIndex(self._mailFailures, matchedFailure);
+ if (isNewFailure) {
+ self._mailFailures[index] = new MailFailure(self, data);
+ } else {
+ self._mailFailures.splice(index, 1);
+ }
+ } else if (isNewFailure) {
+ self._mailFailures.push(new MailFailure(self, data));
+ }
+ var message = _.find(self._messages, function (msg) {
+ return msg.getID() === data.message_id;
+ });
+ if (message) {
+ message.setSmsStatus(data.sms_id, data.sms_status);
+ self._mailBus.trigger('update_message', message);
+ }
+ });
+ this._mailBus.trigger('update_needaction', this.needactionCounter);
+ },
+});
+
+});
diff --git a/addons/sms/static/src/js/systray_messaging_menu.js b/addons/sms/static/src/js/systray_messaging_menu.js
new file mode 100644
index 00000000000..80987af37e6
--- /dev/null
+++ b/addons/sms/static/src/js/systray_messaging_menu.js
@@ -0,0 +1,80 @@
+odoo.define('sms.systray.MessagingMenu', function (require) {
+"use strict";
+
+var core = require('web.core');
+var MessagingMenu = require('mail.systray.MessagingMenu');
+
+var _t = core._t;
+
+MessagingMenu.include({
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called when clicking on a preview related to a snailmail failure
+ *
+ * @private
+ * @param {$.Element} $target DOM of preview element clicked
+ */
+ _clickSMSFailurePreview: function ($target) {
+ var documentID = $target.data('document-id');
+ var documentModel = $target.data('document-model');
+ if (documentModel && documentID) {
+ this._openDocument(documentModel, documentID);
+ } else if (documentModel !== 'mail.channel') {
+ // preview of SMS failures grouped to different document of same model
+ this.do_action({
+ name: _t('SMS Failures'),
+ type: 'ir.actions.act_window',
+ view_mode: 'kanban,list,form',
+ views: [[false, 'kanban'], [false, 'list'], [false, 'form']],
+ target: 'current',
+ res_model: documentModel,
+ domain: [['message_has_sms_error', '=', true]],
+ });
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @override
+ */
+ _onClickPreview: function (ev) {
+ var $target = $(ev.currentTarget);
+ var previewID = $target.data('preview-id');
+ if (previewID === 'sms_failure') {
+ this._clickSMSFailurePreview($target);
+ } else {
+ this._super.apply(this, arguments);
+ }
+ },
+ /**
+ * @private
+ * @override
+ */
+ _onClickPreviewMarkAsRead: function (ev) {
+ ev.stopPropagation();
+ var $preview = $(ev.currentTarget).closest('.o_mail_preview');
+ var previewID = $preview.data('preview-id');
+ if (previewID === 'sms_failure') {
+ var documentModel = $preview.data('document-model');
+ var unreadCounter = $preview.data('unread-counter');
+ this.do_action('sms.sms_cancel_action', {
+ additional_context: {
+ default_model: documentModel,
+ unread_counter: unreadCounter
+ }
+ });
+ } else {
+ this._super.apply(this, arguments);
+ }
+ },
+});
+
+});
diff --git a/addons/sms/static/src/js/thread_widget.js b/addons/sms/static/src/js/thread_widget.js
new file mode 100644
index 00000000000..4655732b34d
--- /dev/null
+++ b/addons/sms/static/src/js/thread_widget.js
@@ -0,0 +1,89 @@
+odoo.define('sms.widget.Thread', function (require) {
+"use strict";
+
+var ThreadWidget = require('mail.widget.Thread');
+var core = require('web.core');
+
+var QWeb = core.qweb;
+
+ThreadWidget.include({
+ events: _.extend({}, ThreadWidget.prototype.events, {
+ 'click .o_thread_message_sms_error': '_onClickSMSError'
+ }),
+ /**
+ * @override
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ this._enabledOptions = _.defaults(this._enabledOptions, {
+ displaySmsIcons: true,
+ });
+ this._disabledOptions = _.defaults(this._disabledOptions, {
+ displaySmsIcons: false,
+ });
+ },
+ /**
+ * @override
+ */
+ render: function (thread, options) {
+ this._super.apply(this, arguments);
+ var messages = _.clone(thread.getMessages({domain: options.domain || []}));
+ this._renderMessageSmsPopover(messages);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Render the popover when mouse-hovering on the mail icon of a message
+ * in the thread. There is at most one such popover at any given time.
+ *
+ * @private
+ * @param {mail.model.AbstractMessage[]} messages list of messages in the
+ * rendered thread, for which popover on mouseover interaction is
+ * permitted.
+ */
+ _renderMessageSmsPopover: function (messages) {
+ if (this._messageSmsPopover) {
+ this._messageSmsPopover.popover('hide');
+ }
+ if (!this.$('.o_thread_sms_tooltip').length) {
+ return;
+ }
+ this._messageSmsPopover = this.$('.o_thread_sms_tooltip').popover({
+ html: true,
+ boundary: 'viewport',
+ placement: 'auto',
+ trigger: 'hover',
+ offset: '0, 1',
+ content: function () {
+ var messageID = $(this).data('message-id');
+ var message = _.find(messages, function (message) {
+ return message.getID() === messageID;
+ });
+ return QWeb.render('sms.widget.Thread.Message.SmsTooltip', {
+ data: message.getSmsIds()
+ });
+ },
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onClickSMSError: function (ev) {
+ var messageID = $(ev.currentTarget).data('message-id');
+ this.do_action('sms.sms_resend_action', {
+ additional_context: {
+ default_mail_message_id: messageID
+ }
+ });
+ },
+});
+});
diff --git a/addons/sms/static/src/scss/thread.scss b/addons/sms/static/src/scss/thread.scss
new file mode 100644
index 00000000000..ba4e54386c7
--- /dev/null
+++ b/addons/sms/static/src/scss/thread.scss
@@ -0,0 +1,5 @@
+i.o_thread_message_sms.o_thread_message_sms_error {
+ color: red;
+ opacity: 1;
+ cursor: pointer;
+}
diff --git a/addons/sms/static/src/xml/sms_widget.xml b/addons/sms/static/src/xml/sms_widget.xml
deleted file mode 100644
index 62d356e3a70..00000000000
--- a/addons/sms/static/src/xml/sms_widget.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<templates>
- <t t-name="sms.sms_count">
- <span class="float-right"><span class="text-muted o_sms_count"></span> <a href="https://iap-services.odoo.com/iap/sms/pricing" target="_blank" class="fa fa-lg fa-info-circle" aria-label="SMS Pricing" title="SMS Pricing"/></span>
- </t>
-</templates>
diff --git a/addons/sms/static/src/xml/thread.xml b/addons/sms/static/src/xml/thread.xml
new file mode 100644
index 00000000000..b01524ba609
--- /dev/null
+++ b/addons/sms/static/src/xml/thread.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template id="template" xml:space="preserve">
+
+ <t t-extend="mail.widget.Thread.Message">
+ <t t-jquery=".o_thread_tooltip_container" t-operation="after">
+ <span t-if="message.getType() === 'sms' and options.displaySmsIcons" class="o_thread_sms_tooltip_container">
+ <t t-set="thread_icon_class" t-value="'o_thread_sms_tooltip o_thread_message_sms o_thread_message_sms_' + message.getSmsStatus()" />
+ <i t-attf-class="o_thread_sms_tooltip o_thread_message_sms o_thread_message_sms_#{message.getSmsStatus()} #{message.isError() ? 'o_thread_message_sms_error' : ''} fa fa-comment"
+ t-att-data-message-id="message.getID()"/>
+ </span>
+ </t>
+ </t>
+
+ <t t-name="sms.widget.Thread.Message.SmsTooltip">
+ <div t-foreach="data" t-as="customerSMSData">
+ <span class="d-inline-block text-center o_thread_tooltip_icon">
+ <i t-if="customerSMSData[2] === 'sent'" class='fa fa-check' title="Sent" role="img" aria-label="Sent"/>
+ <i t-if="customerSMSData[2] === 'canceled'" class='fa fa-trash-o' title="Canceled" role="img" aria-label="Canceled"/>
+ <i t-if="customerSMSData[2] === 'outgoing'" class='fa fa-clock-o' title="Awaiting Dispatch" role="img" aria-label="Awaiting Dispatch"/>
+ <i t-if="customerSMSData[2] === 'exception'" class='fa fa-exclamation text-danger' title="Error" role="img" aria-label="Error"/>
+ </span>
+ <span t-esc="customerSMSData[1]"/>
+ </div>
+ </t>
+
+ </template>