diff --git a/components/at_mention/at_mention.jsx b/components/at_mention/at_mention.jsx index 9d832657d4ac..63ae81422fde 100644 --- a/components/at_mention/at_mention.jsx +++ b/components/at_mention/at_mention.jsx @@ -9,7 +9,7 @@ import {Client4} from 'mattermost-redux/client'; import Pluggable from 'plugins/pluggable'; -import ProfilePopover from 'components/profile_popover.jsx'; +import ProfilePopover from 'components/profile_popover_new.jsx'; export default class AtMention extends React.PureComponent { static propTypes = { @@ -95,6 +95,7 @@ export default class AtMention extends React.PureComponent { hide={this.hideProfilePopover} isRHS={this.props.isRHS} hasMention={this.props.hasMention} + parent={this} /> } diff --git a/components/profile_picture.jsx b/components/profile_picture.jsx index 0194ed8adb59..52ee492adedc 100644 --- a/components/profile_picture.jsx +++ b/components/profile_picture.jsx @@ -10,7 +10,7 @@ import Pluggable from 'plugins/pluggable'; import * as PostUtils from 'utils/post_utils.jsx'; -import ProfilePopover from './profile_popover.jsx'; +import ProfilePopover from './profile_popover_new.jsx'; import StatusIcon from './status_icon.jsx'; export default class ProfilePicture extends React.PureComponent { @@ -18,7 +18,8 @@ export default class ProfilePicture extends React.PureComponent { width: '36', height: '36', isRHS: false, - hasMention: false + hasMention: false, + disablePopover: false }; static propTypes = { @@ -30,7 +31,8 @@ export default class ProfilePicture extends React.PureComponent { isBusy: PropTypes.bool, isRHS: PropTypes.bool, hasMention: PropTypes.bool, - post: PropTypes.object + post: PropTypes.object, + disablePopover: PropTypes.bool }; hideProfilePopover = () => { @@ -44,7 +46,7 @@ export default class ProfilePicture extends React.PureComponent { if (this.props.post) { isSystemMessage = PostUtils.isSystemMessage(this.props.post); } - if (this.props.user) { + if (this.props.user && !this.props.disablePopover) { return ( } diff --git a/components/profile_popover_new.jsx b/components/profile_popover_new.jsx new file mode 100644 index 000000000000..bb416544f372 --- /dev/null +++ b/components/profile_popover_new.jsx @@ -0,0 +1,363 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import PropTypes from 'prop-types'; +import React from 'react'; +import {OverlayTrigger, Popover, Tooltip} from 'react-bootstrap'; +import {browserHistory} from 'react-router'; + +import {openDirectChannelToUser} from 'actions/channel_actions.jsx'; +import * as GlobalActions from 'actions/global_actions.jsx'; +import * as WebrtcActions from 'actions/webrtc_actions.jsx'; +import TeamStore from 'stores/team_store.jsx'; +import UserStore from 'stores/user_store.jsx'; +import WebrtcStore from 'stores/webrtc_store.jsx'; + +import Constants from 'utils/constants.jsx'; +import * as Utils from 'utils/utils.jsx'; + +const UserStatuses = Constants.UserStatuses; + +import emailIcon from 'images/icons/email_cta.png'; +import dmIcon from 'images/icons/dm_cta.png'; +import calendarIcon from 'images/icons/calendar_cta.png'; + +class ProfilePopoverNew extends React.Component { + static getComponentName() { + return 'ProfilePopoverNew'; + } + + static propTypes = { + + /** + * Source URL from the image to display in the popover + */ + src: PropTypes.string.isRequired, + + /** + * User the popover is being opened for + */ + user: PropTypes.object.isRequired, + + /** + * Status for the user, either 'offline', 'away', 'dnd' or 'online' + */ + status: PropTypes.string, + + /** + * Set to true if the user is in a WebRTC call + */ + isBusy: PropTypes.bool, + + /** + * Function to call to hide the popover + */ + hide: PropTypes.func, + + /** + * Set to true if the popover was opened from the right-hand + * sidebar (comment thread, search results, etc.) + */ + isRHS: PropTypes.bool, + + /** + * @internal + */ + hasMention: PropTypes.bool, + + /** + * @internal + */ + parent: PropTypes.object, + + ...Popover.propTypes + } + + static defaultProps = { + isRHS: false, + hasMention: false + } + + constructor(props) { + super(props); + + this.initWebrtc = this.initWebrtc.bind(this); + this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this); + this.handleMentionKeyClick = this.handleMentionKeyClick.bind(this); + this.state = { + currentUserId: UserStore.getCurrentId(), + loadingDMChannel: false + }; + } + shouldComponentUpdate(nextProps) { + if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) { + return true; + } + + if (nextProps.src !== this.props.src) { + return true; + } + + if (nextProps.status !== this.props.status) { + return true; + } + + if (nextProps.isBusy !== this.props.isBusy) { + return true; + } + + // React-Bootstrap Forwarded Props from OverlayTrigger to Popover + if (nextProps.arrowOffsetLeft !== this.props.arrowOffsetLeft) { + return true; + } + + if (nextProps.arrowOffsetTop !== this.props.arrowOffsetTop) { + return true; + } + + if (nextProps.positionLeft !== this.props.positionLeft) { + return true; + } + + if (nextProps.positionTop !== this.props.positionTop) { + return true; + } + + return false; + } + + handleShowDirectChannel(e) { + e.preventDefault(); + + if (!this.props.user) { + return; + } + + const user = this.props.user; + + if (this.state.loadingDMChannel) { + return; + } + + this.setState({loadingDMChannel: true}); + + openDirectChannelToUser( + user.id, + (channel) => { + if (Utils.isMobile()) { + GlobalActions.emitCloseRightHandSide(); + } + this.setState({loadingDMChannel: false}); + 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(); + WebrtcActions.initWebrtc(this.props.user.id, true); + } + } + + handleMentionKeyClick(e) { + e.preventDefault(); + + if (!this.props.user) { + return; + } + if (this.props.hide) { + this.props.hide(); + } + GlobalActions.emitPopoverMentionKeyClick(this.props.isRHS, this.props.user.username); + } + + render() { + const popoverProps = Object.assign({}, this.props); + delete popoverProps.user; + delete popoverProps.src; + delete popoverProps.parent; + delete popoverProps.status; + delete popoverProps.isBusy; + delete popoverProps.hide; + delete popoverProps.isRHS; + delete popoverProps.hasMention; + delete popoverProps.dispatch; + + const email = this.props.user.email; + const username = this.props.user.username; + var dataContent = []; + var dataContentIcons = []; + var showEmail = global.window.mm_config.ShowEmailAddress === 'true' || UserStore.isSystemAdminForCurrentUser() || this.props.user.id === UserStore.getCurrentId(); + var showDirectChannel = this.props.user.id !== UserStore.getCurrentId(); + const fullname = Utils.getFullName(this.props.user); + const firstname = this.props.user.first_name; + if (fullname) { + dataContent.push( + {`See ${firstname}'s whober profile`} + )} + > +
+

+ + {fullname} + +

+
+
+ ); + } + + if (this.props.user.position) { + dataContent.push( + {this.props.user.position}} + > +
+ {this.props.user.position} +
+
+ ); + } + + if (showDirectChannel) { + dataContentIcons.push( +
+ + + +
+ ); + } + if (showEmail) { + dataContentIcons.push( +
+ + + +
+ ); + } + dataContentIcons.push( +
+ + + +
+ ); + if (showEmail || showDirectChannel) { + dataContent.push( +
+ {dataContentIcons} +
+ ); + } + if (username && firstname) { + dataContent.push( + {`Mention to ${firstname}`} + )} + > + + + ); + } + + return ( + +
+ + {dataContent} +
+
+ ); + } +} + +delete ProfilePopoverNew.propTypes.id; + +export default ProfilePopoverNew; diff --git a/components/search_results_item.jsx b/components/search_results_item.jsx index fd2c1b4363ac..986a3634d515 100644 --- a/components/search_results_item.jsx +++ b/components/search_results_item.jsx @@ -185,13 +185,11 @@ export default class SearchResultsItem extends React.Component { } let overrideUsername; - let disableProfilePopover = false; if (post.props && post.props.from_webhook && post.props.override_username && global.window.mm_config.EnablePostUsernameOverride === 'true') { overrideUsername = post.props.override_username; - disableProfilePopover = true; } let botIndicator; @@ -205,6 +203,7 @@ export default class SearchResultsItem extends React.Component { user={this.props.user} status={this.props.status} isBusy={this.props.isBusy} + disablePopover={true} /> ); @@ -322,7 +321,7 @@ export default class SearchResultsItem extends React.Component { diff --git a/components/sidebar_header.jsx b/components/sidebar_header.jsx index 70cf3fd07627..47cf38aeac51 100644 --- a/components/sidebar_header.jsx +++ b/components/sidebar_header.jsx @@ -81,6 +81,8 @@ export default class SidebarHeader extends React.Component { } let teamNameWithToolTip = null; + + /* if (this.props.teamDescription === '') { teamNameWithToolTip = (
); } else { - var me = this.props.currentUser; - const fullName = Utils.getFullName(me); - teamNameWithToolTip = ( - - {fullName} - - )} - ref='descriptionOverlay' - > -
{fullName} -
-
- ); - } + + )} + ref='descriptionOverlay' + > +
+ {fullName} +
+ + ); + + // } return (
} diff --git a/images/icons/calendar_cta.png b/images/icons/calendar_cta.png new file mode 100644 index 000000000000..2ecdb018b1f2 Binary files /dev/null and b/images/icons/calendar_cta.png differ diff --git a/images/icons/dm_cta.png b/images/icons/dm_cta.png new file mode 100644 index 000000000000..0eddc59fa546 Binary files /dev/null and b/images/icons/dm_cta.png differ diff --git a/images/icons/email_cta.png b/images/icons/email_cta.png new file mode 100644 index 000000000000..b44079f2dbea Binary files /dev/null and b/images/icons/email_cta.png differ diff --git a/sass/components/_popover.scss b/sass/components/_popover.scss index 27a959a03ed3..0bc2b8d72b6b 100644 --- a/sass/components/_popover.scss +++ b/sass/components/_popover.scss @@ -68,7 +68,6 @@ background: transparent; border: none; box-shadow: none; - top: -190px !important; .popover-title, .arrow { display: none; } @@ -103,6 +102,11 @@ margin-bottom: 0; } } + .profile-popover-position { + font-size: 12px; + max-width: 185px; + margin: 0 8px; + } .profile-popover-icons { margin: 0 auto; .profile-popover-icon {