PLT-3132 Add a direct message link to the contact pop-over (#4853)

* added DM button to the user picture and name popover

* removed isRequired from status and busy properties from profile_popover.jsx
Этот коммит содержится в:
khawerrind
2016-12-30 21:48:37 +05:00
коммит произвёл enahum
родитель 89f1e8fc0c
Коммит 28a7a2f200
6 изменённых файлов: 109 добавлений и 3 удалений

Просмотреть файл

@@ -7,6 +7,11 @@ import React from 'react';
import {OverlayTrigger} from 'react-bootstrap'; import {OverlayTrigger} from 'react-bootstrap';
export default class ProfilePicture extends React.Component { export default class ProfilePicture extends React.Component {
constructor(props) {
super(props);
this.hideProfilePopover = this.hideProfilePopover.bind(this);
}
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) {
return true; return true;
@@ -35,6 +40,10 @@ export default class ProfilePicture extends React.Component {
return false; return false;
} }
hideProfilePopover() {
this.refs.overlay.hide();
}
render() { render() {
let statusClass = ''; let statusClass = '';
if (this.props.status) { if (this.props.status) {
@@ -43,6 +52,7 @@ export default class ProfilePicture extends React.Component {
if (this.props.user) { if (this.props.user) {
return ( return (
<OverlayTrigger <OverlayTrigger
ref='overlay'
trigger='click' trigger='click'
placement='right' placement='right'
rootClose={true} rootClose={true}
@@ -52,6 +62,7 @@ export default class ProfilePicture extends React.Component {
src={this.props.src} src={this.props.src}
status={this.props.status} status={this.props.status}
isBusy={this.props.isBusy} isBusy={this.props.isBusy}
hide={this.hideProfilePopover}
/> />
} }
> >

Просмотреть файл

@@ -4,14 +4,17 @@
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import UserStore from 'stores/user_store.jsx'; import UserStore from 'stores/user_store.jsx';
import WebrtcStore from 'stores/webrtc_store.jsx'; import WebrtcStore from 'stores/webrtc_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import * as GlobalActions from 'actions/global_actions.jsx'; import * as GlobalActions from 'actions/global_actions.jsx';
import * as WebrtcActions from 'actions/webrtc_actions.jsx'; import * as WebrtcActions from 'actions/webrtc_actions.jsx';
import {openDirectChannelToUser} from 'actions/channel_actions.jsx';
import Constants from 'utils/constants.jsx'; import Constants from 'utils/constants.jsx';
const UserStatuses = Constants.UserStatuses; const UserStatuses = Constants.UserStatuses;
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES; const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
import {Popover, OverlayTrigger, Tooltip} from 'react-bootstrap'; import {Popover, OverlayTrigger, Tooltip} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {browserHistory} from 'react-router/es6';
import React from 'react'; import React from 'react';
export default class ProfilePopover extends React.Component { export default class ProfilePopover extends React.Component {
@@ -19,8 +22,10 @@ export default class ProfilePopover extends React.Component {
super(props); super(props);
this.initWebrtc = this.initWebrtc.bind(this); this.initWebrtc = this.initWebrtc.bind(this);
this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
this.state = { this.state = {
currentUserId: UserStore.getCurrentId() currentUserId: UserStore.getCurrentId(),
loadingDMChannel: -1
}; };
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
@@ -60,6 +65,33 @@ export default class ProfilePopover extends React.Component {
return false; return false;
} }
handleShowDirectChannel(e) {
e.preventDefault();
if (!this.props.user) {
return;
}
const user = this.props.user;
if (this.state.loadingDMChannel !== -1) {
return;
}
this.setState({loadingDMChannel: user.id});
openDirectChannelToUser(
user,
(channel) => {
this.setState({loadingDMChannel: -1});
if (this.props.hide) {
this.props.hide();
}
browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name);
}
);
}
initWebrtc() { initWebrtc() {
if (this.props.status !== UserStatuses.OFFLINE && !WebrtcStore.isBusy()) { if (this.props.status !== UserStatuses.OFFLINE && !WebrtcStore.isBusy()) {
GlobalActions.emitCloseRightHandSide(); GlobalActions.emitCloseRightHandSide();
@@ -73,6 +105,7 @@ export default class ProfilePopover extends React.Component {
delete popoverProps.src; delete popoverProps.src;
delete popoverProps.status; delete popoverProps.status;
delete popoverProps.isBusy; delete popoverProps.isBusy;
delete popoverProps.hide;
let webrtc; let webrtc;
const userMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; const userMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
@@ -203,6 +236,28 @@ export default class ProfilePopover extends React.Component {
); );
} }
if (this.props.user.id !== UserStore.getCurrentId()) {
dataContent.push(
<div
data-toggle='tooltip'
key='user-popover-dm'
className='popover-dm__content'
>
<a
href='#'
className='text-nowrap text-lowercase user-popover__email'
onClick={this.handleShowDirectChannel}
>
<i className='fa fa-paper-plane'/>
<FormattedMessage
id='user_profile.send.dm'
defaultMessage='Send Message'
/>
</a>
</div>
);
}
return ( return (
<Popover <Popover
{...popoverProps} {...popoverProps}
@@ -218,7 +273,8 @@ export default class ProfilePopover extends React.Component {
ProfilePopover.propTypes = Object.assign({ ProfilePopover.propTypes = Object.assign({
src: React.PropTypes.string.isRequired, src: React.PropTypes.string.isRequired,
user: React.PropTypes.object.isRequired, user: React.PropTypes.object.isRequired,
status: React.PropTypes.string.isRequired, status: React.PropTypes.string,
isBusy: React.PropTypes.bool.isRequired isBusy: React.PropTypes.bool,
hide: React.PropTypes.func
}, Popover.propTypes); }, Popover.propTypes);
delete ProfilePopover.propTypes.id; delete ProfilePopover.propTypes.id;

Просмотреть файл

@@ -10,6 +10,11 @@ import {OverlayTrigger} from 'react-bootstrap';
import React from 'react'; import React from 'react';
export default class UserProfile extends React.Component { export default class UserProfile extends React.Component {
constructor(props) {
super(props);
this.hideProfilePopover = this.hideProfilePopover.bind(this);
}
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) {
return true; return true;
@@ -42,6 +47,10 @@ export default class UserProfile extends React.Component {
return false; return false;
} }
hideProfilePopover() {
this.refs.overlay.hide();
}
render() { render() {
let name = '...'; let name = '...';
let profileImg = ''; let profileImg = '';
@@ -60,6 +69,7 @@ export default class UserProfile extends React.Component {
return ( return (
<OverlayTrigger <OverlayTrigger
ref='overlay'
trigger='click' trigger='click'
placement='right' placement='right'
rootClose={true} rootClose={true}
@@ -69,6 +79,7 @@ export default class UserProfile extends React.Component {
src={profileImg} src={profileImg}
status={this.props.status} status={this.props.status}
isBusy={this.props.isBusy} isBusy={this.props.isBusy}
hide={this.hideProfilePopover}
/> />
} }
> >

Просмотреть файл

@@ -2162,6 +2162,7 @@
"user.settings.security.title": "Security Settings", "user.settings.security.title": "Security Settings",
"user.settings.security.viewHistory": "View Access History", "user.settings.security.viewHistory": "View Access History",
"user_list.notFound": "No users found", "user_list.notFound": "No users found",
"user_profile.send.dm": "Send Message",
"user_profile.webrtc.call": "Start Video Call", "user_profile.webrtc.call": "Start Video Call",
"user_profile.webrtc.offline": "The user is offline", "user_profile.webrtc.offline": "The user is offline",
"user_profile.webrtc.unavailable": "New call unavailable until your existing call ends", "user_profile.webrtc.unavailable": "New call unavailable until your existing call ends",

Просмотреть файл

@@ -34,6 +34,32 @@
} }
} }
} }
.popover-dm__content {
-webkit-border-radius: 0;
-moz-border-radius: 0;
-ms-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
max-width: 100%;
overflow: hidden;
padding: 5px 5px 5px 0px;
text-overflow: ellipsis;
margin: 0;
font-size: 14px;
border-top: 1px solid #ebebeb;
border-color: rgba(221, 221, 221, 0.2);
margin-top: 5px;
margin-bottom: -5px;
> a {
> i {
margin-right: 5px;
}
> span {
text-transform: capitalize;
}
}
}
} }
.channel-header__info { .channel-header__info {

Просмотреть файл

@@ -595,6 +595,7 @@ export function applyTheme(theme) {
changeCss('.app__body .popover.left>.arrow', 'border-left-color:' + changeOpacity(theme.centerChannelColor, 0.25)); changeCss('.app__body .popover.left>.arrow', 'border-left-color:' + changeOpacity(theme.centerChannelColor, 0.25));
changeCss('.app__body .popover.top>.arrow', 'border-top-color:' + changeOpacity(theme.centerChannelColor, 0.25)); changeCss('.app__body .popover.top>.arrow', 'border-top-color:' + changeOpacity(theme.centerChannelColor, 0.25));
changeCss('.app__body .suggestion-list__content .command, .app__body .popover .popover-title', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2)); changeCss('.app__body .suggestion-list__content .command, .app__body .popover .popover-title', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
changeCss('.app__body .suggestion-list__content .command, .app__body .popover .popover-dm__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
changeCss('.app__body .suggestion-list__divider:before, .app__body .dropdown-menu .divider, .app__body .search-help-popover .search-autocomplete__divider:before', 'background:' + theme.centerChannelColor); changeCss('.app__body .suggestion-list__divider:before, .app__body .dropdown-menu .divider, .app__body .search-help-popover .search-autocomplete__divider:before', 'background:' + theme.centerChannelColor);
changeCss('.app__body .custom-textarea', 'color:' + theme.centerChannelColor); changeCss('.app__body .custom-textarea', 'color:' + theme.centerChannelColor);
changeCss('.app__body .post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2)); changeCss('.app__body .post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));