diff options
-rw-r--r-- | webapp/components/profile_picture.jsx | 11 | ||||
-rw-r--r-- | webapp/components/profile_popover.jsx | 62 | ||||
-rw-r--r-- | webapp/components/user_profile.jsx | 11 | ||||
-rw-r--r-- | webapp/i18n/en.json | 1 | ||||
-rw-r--r-- | webapp/sass/components/_popover.scss | 26 | ||||
-rw-r--r-- | webapp/utils/utils.jsx | 1 |
6 files changed, 109 insertions, 3 deletions
diff --git a/webapp/components/profile_picture.jsx b/webapp/components/profile_picture.jsx index 17a4ddc65..26e9f30d9 100644 --- a/webapp/components/profile_picture.jsx +++ b/webapp/components/profile_picture.jsx @@ -7,6 +7,11 @@ import React from 'react'; import {OverlayTrigger} from 'react-bootstrap'; export default class ProfilePicture extends React.Component { + constructor(props) { + super(props); + + this.hideProfilePopover = this.hideProfilePopover.bind(this); + } shouldComponentUpdate(nextProps) { if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { return true; @@ -35,6 +40,10 @@ export default class ProfilePicture extends React.Component { return false; } + hideProfilePopover() { + this.refs.overlay.hide(); + } + render() { let statusClass = ''; if (this.props.status) { @@ -43,6 +52,7 @@ export default class ProfilePicture extends React.Component { if (this.props.user) { return ( <OverlayTrigger + ref='overlay' trigger='click' placement='right' rootClose={true} @@ -52,6 +62,7 @@ export default class ProfilePicture extends React.Component { src={this.props.src} status={this.props.status} isBusy={this.props.isBusy} + hide={this.hideProfilePopover} /> } > diff --git a/webapp/components/profile_popover.jsx b/webapp/components/profile_popover.jsx index 8b431b643..d7d9929ee 100644 --- a/webapp/components/profile_popover.jsx +++ b/webapp/components/profile_popover.jsx @@ -4,14 +4,17 @@ import * as Utils from 'utils/utils.jsx'; import UserStore from 'stores/user_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 WebrtcActions from 'actions/webrtc_actions.jsx'; +import {openDirectChannelToUser} from 'actions/channel_actions.jsx'; import Constants from 'utils/constants.jsx'; const UserStatuses = Constants.UserStatuses; const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES; import {Popover, OverlayTrigger, Tooltip} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; +import {browserHistory} from 'react-router/es6'; import React from 'react'; export default class ProfilePopover extends React.Component { @@ -19,8 +22,10 @@ export default class ProfilePopover extends React.Component { super(props); this.initWebrtc = this.initWebrtc.bind(this); + this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this); this.state = { - currentUserId: UserStore.getCurrentId() + currentUserId: UserStore.getCurrentId(), + loadingDMChannel: -1 }; } shouldComponentUpdate(nextProps) { @@ -60,6 +65,33 @@ export default class ProfilePopover extends React.Component { 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() { if (this.props.status !== UserStatuses.OFFLINE && !WebrtcStore.isBusy()) { GlobalActions.emitCloseRightHandSide(); @@ -73,6 +105,7 @@ export default class ProfilePopover extends React.Component { delete popoverProps.src; delete popoverProps.status; delete popoverProps.isBusy; + delete popoverProps.hide; let webrtc; 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 ( <Popover {...popoverProps} @@ -218,7 +273,8 @@ export default class ProfilePopover extends React.Component { ProfilePopover.propTypes = Object.assign({ src: React.PropTypes.string.isRequired, user: React.PropTypes.object.isRequired, - status: React.PropTypes.string.isRequired, - isBusy: React.PropTypes.bool.isRequired + status: React.PropTypes.string, + isBusy: React.PropTypes.bool, + hide: React.PropTypes.func }, Popover.propTypes); delete ProfilePopover.propTypes.id; diff --git a/webapp/components/user_profile.jsx b/webapp/components/user_profile.jsx index 807c5f023..d0267c0d8 100644 --- a/webapp/components/user_profile.jsx +++ b/webapp/components/user_profile.jsx @@ -10,6 +10,11 @@ import {OverlayTrigger} from 'react-bootstrap'; import React from 'react'; export default class UserProfile extends React.Component { + constructor(props) { + super(props); + + this.hideProfilePopover = this.hideProfilePopover.bind(this); + } shouldComponentUpdate(nextProps) { if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { return true; @@ -42,6 +47,10 @@ export default class UserProfile extends React.Component { return false; } + hideProfilePopover() { + this.refs.overlay.hide(); + } + render() { let name = '...'; let profileImg = ''; @@ -60,6 +69,7 @@ export default class UserProfile extends React.Component { return ( <OverlayTrigger + ref='overlay' trigger='click' placement='right' rootClose={true} @@ -69,6 +79,7 @@ export default class UserProfile extends React.Component { src={profileImg} status={this.props.status} isBusy={this.props.isBusy} + hide={this.hideProfilePopover} /> } > diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index ecc25e42f..641c8daa8 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -2162,6 +2162,7 @@ "user.settings.security.title": "Security Settings", "user.settings.security.viewHistory": "View Access History", "user_list.notFound": "No users found", + "user_profile.send.dm": "Send Message", "user_profile.webrtc.call": "Start Video Call", "user_profile.webrtc.offline": "The user is offline", "user_profile.webrtc.unavailable": "New call unavailable until your existing call ends", diff --git a/webapp/sass/components/_popover.scss b/webapp/sass/components/_popover.scss index 1bd1f2c3b..b4839bd1f 100644 --- a/webapp/sass/components/_popover.scss +++ b/webapp/sass/components/_popover.scss @@ -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 { diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 38d59a82c..1ddb28690 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -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.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-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 .custom-textarea', 'color:' + theme.centerChannelColor); changeCss('.app__body .post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2)); |