[FIX] mail: add the ability to invite on mobile
Before this commit, it was impossible for a user to invite people to a channel or a group DM. This commit add the invite button on the chat windows header only on mobile. Part of task-2634175 closes odoo/odoo#78267 X-original-commit: 56ab9ffea28dd5f22a74ba269cbd5552c42953e3 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
committed by
Sébastien Theys
parent
b57b884430
commit
2e2b49931f
@@ -2,11 +2,6 @@
|
||||
// Layout
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.o_ChannelInvitationForm {
|
||||
width: Min(95vw, 400px);
|
||||
max-height: Min(calc(100vh - 140px), 530px);
|
||||
}
|
||||
|
||||
.o_ChannelInvitationForm_selectablePartnerAvatarContainer {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
overflow: auto;
|
||||
|
||||
&:not(.o-mobile) {
|
||||
max-width: 100%;
|
||||
@@ -32,6 +33,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.o_ChatWindow_channelInvitationForm {
|
||||
min-height: 450px; // allow flex shrink smaller than content (but not too small)
|
||||
}
|
||||
|
||||
.o_ChatWindow_header {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
<t t-if="chatWindow.thread and chatWindow.thread.hasMemberListFeature and chatWindow.isMemberListOpened">
|
||||
<ChannelMemberList channelLocalId="chatWindow.thread.localId" class="bg-white"/>
|
||||
</t>
|
||||
<t t-if="chatWindow.threadView and !chatWindow.isMemberListOpened">
|
||||
<t t-if="chatWindow.channelInvitationForm">
|
||||
<ChannelInvitationForm class="o_ChatWindow_channelInvitationForm" localId="chatWindow.channelInvitationForm.localId"/>
|
||||
</t>
|
||||
<t t-if="chatWindow.threadView">
|
||||
<ThreadView
|
||||
class="o_ChatWindow_thread"
|
||||
hasComposerCurrentPartnerAvatar="false"
|
||||
|
||||
@@ -51,6 +51,7 @@ export class ChatWindowHeader extends Component {
|
||||
*/
|
||||
_onClick(ev) {
|
||||
if (
|
||||
isEventHandled(ev, 'ChatWindow.onClickCommand') ||
|
||||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftNext') ||
|
||||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftPrev') ||
|
||||
isEventHandled(ev, 'ChatWindow.onClickHideMemberList') ||
|
||||
|
||||
@@ -33,6 +33,18 @@
|
||||
<i class="fa fa-phone"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="chatWindow.hasInviteFeature">
|
||||
<t t-if="!chatWindow.channelInvitationForm">
|
||||
<div class="o_ChatWindowHeader_command" title="Add users" t-on-click="chatWindow.onClickShowInviteForm">
|
||||
<i class="fa fa-lg fa-user-plus"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="chatWindow.channelInvitationForm">
|
||||
<div class="o_ChatWindowHeader_command" title="Stop adding users" t-on-click="chatWindow.onClickHideInviteForm">
|
||||
<i class="fa fa-lg fa-user-plus"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="chatWindow.thread and chatWindow.thread.hasMemberListFeature and !chatWindow.isMemberListOpened">
|
||||
<div class="o_ChatWindowHeader_command o_ChatWindowHeader_commandShowMemberList" t-att-class="{ 'o-mobile': messaging.device.isMobile }" title="Show Member List" t-on-click="chatWindow.onClickShowMemberList">
|
||||
<i class="fa fa-users"/>
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
border: $border-width solid;
|
||||
}
|
||||
|
||||
.o_PopoverView_channelInvitationForm {
|
||||
width: Min(95vw, 400px);
|
||||
max-height: Min(calc(100vh - 140px), 530px);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Style
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<t t-name="mail.PopoverView" owl="1">
|
||||
<div class="o_PopoverView">
|
||||
<t t-if="popoverView">
|
||||
<ChannelInvitationForm localId="popoverView.channelInvitationForm.localId"/>
|
||||
<ChannelInvitationForm class="o_PopoverView_channelInvitationForm" localId="popoverView.channelInvitationForm.localId"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, many2many, many2one, one2one } from '@mail/model/model_field';
|
||||
import { clear, insertAndReplace, link, unlink, unlinkAll } from '@mail/model/model_field_command';
|
||||
import { clear, insertAndReplace, link, replace, unlink, unlinkAll } from '@mail/model/model_field_command';
|
||||
import { cleanSearchTerm } from '@mail/utils/utils';
|
||||
|
||||
function factory(dependencies) {
|
||||
@@ -142,14 +142,19 @@ function factory(dependencies) {
|
||||
},
|
||||
{ shadow: true }
|
||||
);
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.update({
|
||||
searchResultCount: count,
|
||||
selectablePartners: insertAndReplace(partnersData.map(partnerData => this.messaging.models['mail.partner'].convertData(partnerData))),
|
||||
});
|
||||
} finally {
|
||||
this.update({ hasSearchRpcInProgress: false });
|
||||
if (this.hasPendingSearchRpc) {
|
||||
this.searchPartnersToInvite();
|
||||
if (this.exists()) {
|
||||
this.update({ hasSearchRpcInProgress: false });
|
||||
if (this.hasPendingSearchRpc) {
|
||||
this.searchPartnersToInvite();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,9 +180,27 @@ function factory(dependencies) {
|
||||
return this.env._t("Invite to Channel");
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {FieldCommand}
|
||||
*/
|
||||
_computeThread() {
|
||||
if (this.threadView && this.threadView.thread) {
|
||||
return replace(this.threadView.thread);
|
||||
}
|
||||
if (this.chatWindow && this.chatWindow.thread) {
|
||||
return replace(this.chatWindow.thread);
|
||||
}
|
||||
return clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ChannelInvitationForm.fields = {
|
||||
chatWindow: one2one('mail.chat_window', {
|
||||
inverse: 'channelInvitationForm',
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* States the OWL component of this channel invitation form.
|
||||
* Useful to be able to close it with popover trigger, or to know when
|
||||
@@ -240,8 +263,8 @@ function factory(dependencies) {
|
||||
* States the thread on which this list operates (if any).
|
||||
*/
|
||||
thread: many2one('mail.thread', {
|
||||
compute: '_computeThread',
|
||||
readonly: true,
|
||||
related: 'threadView.thread',
|
||||
required: true,
|
||||
}),
|
||||
/**
|
||||
@@ -252,7 +275,7 @@ function factory(dependencies) {
|
||||
readonly: true,
|
||||
}),
|
||||
};
|
||||
ChannelInvitationForm.identifyingFields = ['threadView'];
|
||||
ChannelInvitationForm.identifyingFields = [['chatWindow', 'threadView']];
|
||||
ChannelInvitationForm.modelName = 'mail.channel_invitation_form';
|
||||
|
||||
return ChannelInvitationForm;
|
||||
|
||||
@@ -15,7 +15,9 @@ function factory(dependencies) {
|
||||
_created() {
|
||||
super._created();
|
||||
// Bind necessary until OWL supports arrow function in handlers: https://github.com/odoo/owl/issues/876
|
||||
this.onClickHideInviteForm = this.onClickHideInviteForm.bind(this);
|
||||
this.onClickHideMemberList = this.onClickHideMemberList.bind(this);
|
||||
this.onClickShowInviteForm = this.onClickShowInviteForm.bind(this);
|
||||
this.onClickShowMemberList = this.onClickShowMemberList.bind(this);
|
||||
this.onFocusInNewMessageFormInput = this.onFocusInNewMessageFormInput.bind(this);
|
||||
}
|
||||
@@ -127,6 +129,16 @@ function factory(dependencies) {
|
||||
this.manager.swap(this, lastVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles click on the "stop adding users" button.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickHideInviteForm(ev) {
|
||||
markEventHandled(ev, 'ChatWindow.onClickCommand');
|
||||
this.update({ channelInvitationForm: clear() });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
@@ -138,12 +150,33 @@ function factory(dependencies) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles click on the "add users" button.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickShowInviteForm(ev) {
|
||||
markEventHandled(ev, 'ChatWindow.onClickCommand');
|
||||
this.update({
|
||||
channelInvitationForm: insertAndReplace({
|
||||
doFocusOnSearchInput: true,
|
||||
}),
|
||||
isMemberListOpened: false,
|
||||
});
|
||||
if (!this.messaging.isCurrentUserGuest) {
|
||||
this.channelInvitationForm.searchPartnersToInvite();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickShowMemberList(ev) {
|
||||
markEventHandled(ev, 'ChatWindow.onClickShowMemberList');
|
||||
this.update({ isMemberListOpened: true });
|
||||
this.update({
|
||||
channelInvitationForm: clear(),
|
||||
isMemberListOpened: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +227,18 @@ function factory(dependencies) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeHasCallButtons() {
|
||||
return this.thread && this.thread.rtcSessions.length === 0 && ['channel', 'chat', 'group'].includes(this.thread.channel_type);
|
||||
return Boolean(this.thread) && this.thread.rtcSessions.length === 0 && ['channel', 'chat', 'group'].includes(this.thread.channel_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeHasInviteFeature() {
|
||||
return Boolean(
|
||||
this.thread && this.thread.hasInviteFeature &&
|
||||
this.messaging && this.messaging.device && this.messaging.device.isMobile
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,7 +285,7 @@ function factory(dependencies) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeHasThreadView() {
|
||||
return this.isVisible && !this.isFolded && !!this.thread;
|
||||
return this.isVisible && !this.isFolded && !!this.thread && !this.isMemberListOpened && !this.channelInvitationForm;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,6 +412,14 @@ function factory(dependencies) {
|
||||
}
|
||||
|
||||
ChatWindow.fields = {
|
||||
/**
|
||||
* Determines the channel invitation form displayed by this chat window
|
||||
* (if any). Only makes sense if hasInviteFeature is true.
|
||||
*/
|
||||
channelInvitationForm: one2one('mail.channel_invitation_form', {
|
||||
inverse: 'chatWindow',
|
||||
isCausal: true,
|
||||
}),
|
||||
/**
|
||||
* Determines whether the buttons to start a RTC call should be displayed.
|
||||
*/
|
||||
@@ -375,6 +427,12 @@ function factory(dependencies) {
|
||||
default: false,
|
||||
compute: '_computeHasCallButtons',
|
||||
}),
|
||||
/**
|
||||
* States whether this chat window has the invite feature.
|
||||
*/
|
||||
hasInviteFeature: attr({
|
||||
compute: '_computeHasInviteFeature',
|
||||
}),
|
||||
/**
|
||||
* Determines whether "new message form" should be displayed.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user