diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/mail/static/src/components/message_seen_indicator | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mail/static/src/components/message_seen_indicator')
4 files changed, 485 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js new file mode 100644 index 00000000..ed555b0c --- /dev/null +++ b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.js @@ -0,0 +1,136 @@ +odoo.define('mail/static/src/components/message_seen_indicator/message_seen_indicator.js', function (require) { +'use strict'; + +const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js'); +const useStore = require('mail/static/src/component_hooks/use_store/use_store.js'); + +const { Component } = owl; + +class MessageSeenIndicator extends Component { + + /** + * @override + */ + constructor(...args) { + super(...args); + useShouldUpdateBasedOnProps(); + useStore(props => { + const message = this.env.models['mail.message'].get(props.messageLocalId); + const thread = this.env.models['mail.thread'].get(props.threadLocalId); + const messageSeenIndicator = thread && thread.model === 'mail.channel' + ? this.env.models['mail.message_seen_indicator'].findFromIdentifyingData({ + channelId: thread.id, + messageId: message.id, + }) + : undefined; + return { + messageSeenIndicator: messageSeenIndicator ? messageSeenIndicator.__state : undefined, + }; + }); + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @returns {string} + */ + get indicatorTitle() { + if (!this.messageSeenIndicator) { + return ''; + } + if (this.messageSeenIndicator.hasEveryoneSeen) { + return this.env._t("Seen by Everyone"); + } + if (this.messageSeenIndicator.hasSomeoneSeen) { + const partnersThatHaveSeen = this.messageSeenIndicator.partnersThatHaveSeen.map( + partner => partner.name + ); + if (partnersThatHaveSeen.length === 1) { + return _.str.sprintf( + this.env._t("Seen by %s"), + partnersThatHaveSeen[0] + ); + } + if (partnersThatHaveSeen.length === 2) { + return _.str.sprintf( + this.env._t("Seen by %s and %s"), + partnersThatHaveSeen[0], + partnersThatHaveSeen[1] + ); + } + return _.str.sprintf( + this.env._t("Seen by %s, %s and more"), + partnersThatHaveSeen[0], + partnersThatHaveSeen[1] + ); + } + if (this.messageSeenIndicator.hasEveryoneFetched) { + return this.env._t("Received by Everyone"); + } + if (this.messageSeenIndicator.hasSomeoneFetched) { + const partnersThatHaveFetched = this.messageSeenIndicator.partnersThatHaveFetched.map( + partner => partner.name + ); + if (partnersThatHaveFetched.length === 1) { + return _.str.sprintf( + this.env._t("Received by %s"), + partnersThatHaveFetched[0] + ); + } + if (partnersThatHaveFetched.length === 2) { + return _.str.sprintf( + this.env._t("Received by %s and %s"), + partnersThatHaveFetched[0], + partnersThatHaveFetched[1] + ); + } + return _.str.sprintf( + this.env._t("Received by %s, %s and more"), + partnersThatHaveFetched[0], + partnersThatHaveFetched[1] + ); + } + return ''; + } + + /** + * @returns {mail.message} + */ + get message() { + return this.env.models['mail.message'].get(this.props.messageLocalId); + } + + /** + * @returns {mail.message_seen_indicator} + */ + get messageSeenIndicator() { + if (!this.thread || this.thread.model !== 'mail.channel') { + return undefined; + } + return this.env.models['mail.message_seen_indicator'].findFromIdentifyingData({ + channelId: this.thread.id, + messageId: this.message.id, + }); + } + + /** + * @returns {mail.Thread} + */ + get thread() { + return this.env.models['mail.thread'].get(this.props.threadLocalId); + } +} + +Object.assign(MessageSeenIndicator, { + props: { + messageLocalId: String, + threadLocalId: String, + }, + template: 'mail.MessageSeenIndicator', +}); + +return MessageSeenIndicator; + +}); diff --git a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.scss b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.scss new file mode 100644 index 00000000..3a9d566e --- /dev/null +++ b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.scss @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------ +// Layout +// ------------------------------------------------------------------ + +.o_MessageSeenIndicator { + display: flex; + position: relative; + flex-wrap: nowrap; +} + +.o_MessageSeenIndicator_icon { + + &.o-first { + padding-left: map-get($spacers, 1); + } + + &.o-second { + position: absolute; + top: -1px; + left: -1px; + } +} + +// ------------------------------------------------------------------ +// Style +// ------------------------------------------------------------------ + +.o_MessageSeenIndicator { + opacity: 0.6; + + &.o-all-seen { + color: $o-brand-odoo; + } + + &:hover { + cursor: pointer; + opacity: 0.8; + } +} diff --git a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.xml b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.xml new file mode 100644 index 00000000..e905afaa --- /dev/null +++ b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates xml:space="preserve"> + + <t t-name="mail.MessageSeenIndicator" owl="1"> + <span class="o_MessageSeenIndicator" t-att-class="{ 'o-all-seen': messageSeenIndicator and messageSeenIndicator.hasEveryoneSeen }" t-att-title="indicatorTitle"> + <t t-if="messageSeenIndicator and !messageSeenIndicator.isMessagePreviousToLastCurrentPartnerMessageSeenByEveryone"> + <t t-if="messageSeenIndicator.hasSomeoneFetched or messageSeenIndicator.hasSomeoneSeen"> + <i class="o_MessageSeenIndicator_icon o-first fa fa-check"/> + </t> + <t t-if="messageSeenIndicator.hasSomeoneSeen"> + <i class="o_MessageSeenIndicator_icon o-second fa fa-check"/> + </t> + </t> + </span> + </t> +</templates> diff --git a/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator_tests.js b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator_tests.js new file mode 100644 index 00000000..fb9c6b8b --- /dev/null +++ b/addons/mail/static/src/components/message_seen_indicator/message_seen_indicator_tests.js @@ -0,0 +1,294 @@ +odoo.define('mail/static/src/components/message_seen_indicator/message_seen_indicator_tests', function (require) { +'use strict'; + +const components = { + MessageSendIndicator: require('mail/static/src/components/message_seen_indicator/message_seen_indicator.js'), +}; +const { + afterEach, + beforeEach, + createRootComponent, + start, +} = require('mail/static/src/utils/test_utils.js'); + +QUnit.module('mail', {}, function () { +QUnit.module('components', {}, function () { +QUnit.module('message_seen_indicator', {}, function () { +QUnit.module('message_seen_indicator_tests.js', { + beforeEach() { + beforeEach(this); + + this.createMessageSeenIndicatorComponent = async ({ message, thread }, otherProps) => { + const props = Object.assign( + { messageLocalId: message.localId, threadLocalId: thread.localId }, + otherProps + ); + await createRootComponent(this, components.MessageSendIndicator, { + props, + target: this.widget.el, + }); + }; + + this.start = async params => { + const { env, widget } = await start(Object.assign({}, params, { + data: this.data, + })); + this.env = env; + this.widget = widget; + }; + }, + afterEach() { + afterEach(this); + }, +}); + +QUnit.test('rendering when just one has received the message', async function (assert) { + assert.expect(3); + + await this.start(); + const thread = this.env.models['mail.thread'].create({ + id: 1000, + model: 'mail.channel', + partnerSeenInfos: [['create', [ + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + partnerId: 10, + }, + { + channelId: 1000, + partnerId: 100, + }, + ]]], + messageSeenIndicators: [['insert', { + channelId: 1000, + messageId: 100, + }]], + }); + const message = this.env.models['mail.message'].insert({ + author: [['insert', { id: this.env.messaging.currentPartner.id, display_name: "Demo User" }]], + body: "<p>Test</p>", + id: 100, + originThread: [['link', thread]], + }); + await this.createMessageSeenIndicatorComponent({ message, thread }); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator', + "should display a message seen indicator component" + ); + assert.doesNotHaveClass( + document.querySelector('.o_MessageSeenIndicator'), + 'o-all-seen', + "indicator component should not be considered as all seen" + ); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator_icon', + "should display only one seen indicator icon" + ); +}); + +QUnit.test('rendering when everyone have received the message', async function (assert) { + assert.expect(3); + + await this.start(); + const thread = this.env.models['mail.thread'].create({ + id: 1000, + model: 'mail.channel', + partnerSeenInfos: [['create', [ + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + partnerId: 10, + }, + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 99 }]], + partnerId: 100, + }, + ]]], + messageSeenIndicators: [['insert', { + channelId: 1000, + messageId: 100, + }]], + }); + const message = this.env.models['mail.message'].insert({ + author: [['insert', { id: this.env.messaging.currentPartner.id, display_name: "Demo User" }]], + body: "<p>Test</p>", + id: 100, + originThread: [['link', thread]], + }); + await this.createMessageSeenIndicatorComponent({ message, thread }); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator', + "should display a message seen indicator component" + ); + assert.doesNotHaveClass( + document.querySelector('.o_MessageSeenIndicator'), + 'o-all-seen', + "indicator component should not be considered as all seen" + ); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator_icon', + "should display only one seen indicator icon" + ); +}); + +QUnit.test('rendering when just one has seen the message', async function (assert) { + assert.expect(3); + + await this.start(); + const thread = this.env.models['mail.thread'].create({ + id: 1000, + model: 'mail.channel', + partnerSeenInfos: [['create', [ + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + lastSeenMessage: [['insert', { id: 100 }]], + partnerId: 10, + }, + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 99 }]], + partnerId: 100, + }, + ]]], + messageSeenIndicators: [['insert', { + channelId: 1000, + messageId: 100, + }]], + }); + const message = this.env.models['mail.message'].insert({ + author: [['insert', { id: this.env.messaging.currentPartner.id, display_name: "Demo User" }]], + body: "<p>Test</p>", + id: 100, + originThread: [['link', thread]], + }); + await this.createMessageSeenIndicatorComponent({ message, thread }); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator', + "should display a message seen indicator component" + ); + assert.doesNotHaveClass( + document.querySelector('.o_MessageSeenIndicator'), + 'o-all-seen', + "indicator component should not be considered as all seen" + ); + assert.containsN( + document.body, + '.o_MessageSeenIndicator_icon', + 2, + "should display two seen indicator icon" + ); +}); + +QUnit.test('rendering when just one has seen & received the message', async function (assert) { + assert.expect(3); + + await this.start(); + const thread = this.env.models['mail.thread'].create({ + id: 1000, + model: 'mail.channel', + partnerSeenInfos: [['create', [ + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + lastSeenMessage: [['insert', { id: 100 }]], + partnerId: 10, + }, + { + channelId: 1000, + partnerId: 100, + }, + ]]], + messageSeenIndicators: [['insert', { + channelId: 1000, + messageId: 100, + }]], + }); + const message = this.env.models['mail.message'].insert({ + author: [['insert', { id: this.env.messaging.currentPartner.id, display_name: "Demo User" }]], + body: "<p>Test</p>", + id: 100, + originThread: [['link', thread]], + }); + await this.createMessageSeenIndicatorComponent({ message, thread }); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator', + "should display a message seen indicator component" + ); + assert.doesNotHaveClass( + document.querySelector('.o_MessageSeenIndicator'), + 'o-all-seen', + "indicator component should not be considered as all seen" + ); + assert.containsN( + document.body, + '.o_MessageSeenIndicator_icon', + 2, + "should display two seen indicator icon" + ); +}); + +QUnit.test('rendering when just everyone has seen the message', async function (assert) { + assert.expect(3); + + await this.start(); + const thread = this.env.models['mail.thread'].create({ + id: 1000, + model: 'mail.channel', + partnerSeenInfos: [['create', [ + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + lastSeenMessage: [['insert', { id: 100 }]], + partnerId: 10, + }, + { + channelId: 1000, + lastFetchedMessage: [['insert', { id: 100 }]], + lastSeenMessage: [['insert', { id: 100 }]], + partnerId: 100, + }, + ]]], + messageSeenIndicators: [['insert', { + channelId: 1000, + messageId: 100, + }]], + }); + const message = this.env.models['mail.message'].insert({ + author: [['insert', { id: this.env.messaging.currentPartner.id, display_name: "Demo User" }]], + body: "<p>Test</p>", + id: 100, + originThread: [['link', thread]], + }); + await this.createMessageSeenIndicatorComponent({ message, thread }); + assert.containsOnce( + document.body, + '.o_MessageSeenIndicator', + "should display a message seen indicator component" + ); + assert.hasClass( + document.querySelector('.o_MessageSeenIndicator'), + 'o-all-seen', + "indicator component should not considered as all seen" + ); + assert.containsN( + document.body, + '.o_MessageSeenIndicator_icon', + 2, + "should display two seen indicator icon" + ); +}); + +}); +}); +}); + +}); |
