PLT-3982 Add statuses to profile pictures in the RHS and popover member list (#3845)

* Added status indicator back to popover member list

* Updating positions of status indicator (#3844)

* Fixed squishy profile pictures and added statuses to RHS pics
Этот коммит содержится в:
Joram Wilander
2016-08-22 20:35:28 -04:00
коммит произвёл Corey Hulen
родитель f0c672e3ad
Коммит c3c62ad2ad
7 изменённых файлов: 74 добавлений и 31 удалений

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

@@ -1,20 +1,21 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information. // See License.txt for license information.
import $ from 'jquery'; import ProfilePicture from 'components/profile_picture.jsx';
import TeamStore from 'stores/team_store.jsx'; import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx'; import UserStore from 'stores/user_store.jsx';
import {Popover, Overlay} from 'react-bootstrap';
import Client from 'client/web_client.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx'; import Constants from 'utils/constants.jsx';
import Client from 'client/web_client.jsx';
import $ from 'jquery';
import React from 'react';
import {Popover, Overlay} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {browserHistory} from 'react-router/es6'; import {browserHistory} from 'react-router/es6';
import React from 'react';
export default class PopoverListMembers extends React.Component { export default class PopoverListMembers extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -89,24 +90,23 @@ export default class PopoverListMembers extends React.Component {
} }
if (name) { if (name) {
if (!m.status) { let status;
var status = UserStore.getStatus(m.id); if (m.status) {
m.status = status ? 'status-' + status : ''; status = m.status;
} else {
status = UserStore.getStatus(m.id);
} }
popoverHtml.push( popoverHtml.push(
<div <div
className='more-modal__row' className='more-modal__row'
key={'popover-member-' + i} key={'popover-member-' + i}
> >
<ProfilePicture
<span className={`more-modal__image-wrapper ${m.status}`}>
<img
className='more-modal__image'
width='26px'
height='26px'
src={`${Client.getUsersRoute()}/${m.id}/image?time=${m.update_at}`} src={`${Client.getUsersRoute()}/${m.id}/image?time=${m.update_at}`}
status={status}
width='26'
height='26'
/> />
</span>
<div className='more-modal__details'> <div className='more-modal__details'>
<div <div
className='more-modal__name' className='more-modal__name'

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

@@ -4,6 +4,7 @@
import UserProfile from './user_profile.jsx'; import UserProfile from './user_profile.jsx';
import FileAttachmentList from './file_attachment_list.jsx'; import FileAttachmentList from './file_attachment_list.jsx';
import PendingPostOptions from 'components/post_view/components/pending_post_options.jsx'; import PendingPostOptions from 'components/post_view/components/pending_post_options.jsx';
import ProfilePicture from 'components/profile_picture.jsx';
import TeamStore from 'stores/team_store.jsx'; import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx'; import UserStore from 'stores/user_store.jsx';
@@ -13,7 +14,7 @@ import {flagPost, unflagPost} from 'actions/post_actions.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx'; import * as Utils from 'utils/utils.jsx';
import Client from 'client/web_client.jsx'; import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx'; import Constants from 'utils/constants.jsx';
import {Tooltip, OverlayTrigger} from 'react-bootstrap'; import {Tooltip, OverlayTrigger} from 'react-bootstrap';
@@ -41,6 +42,10 @@ export default class RhsComment extends React.Component {
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (nextProps.status !== this.props.status) {
return true;
}
if (nextProps.compactDisplay !== this.props.compactDisplay) { if (nextProps.compactDisplay !== this.props.compactDisplay) {
return true; return true;
} }
@@ -75,7 +80,7 @@ export default class RhsComment extends React.Component {
} }
createDropdown() { createDropdown() {
var post = this.props.post; const post = this.props.post;
if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) { if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) {
return ''; return '';
@@ -212,7 +217,7 @@ export default class RhsComment extends React.Component {
} }
render() { render() {
var post = this.props.post; const post = this.props.post;
const flagIcon = Constants.FLAG_ICON_SVG; const flagIcon = Constants.FLAG_ICON_SVG;
var currentUserCss = ''; var currentUserCss = '';
@@ -258,10 +263,11 @@ export default class RhsComment extends React.Component {
} }
let profilePic = ( let profilePic = (
<img <ProfilePicture
src={Client.getUsersRoute() + '/' + post.user_id + '/image?time=' + timestamp} src={PostUtils.getProfilePicSrcForPost(post, timestamp)}
height='36' status={this.props.status}
width='36' width='36'
height='36'
/> />
); );
@@ -385,5 +391,6 @@ RhsComment.propTypes = {
currentUser: React.PropTypes.object.isRequired, currentUser: React.PropTypes.object.isRequired,
compactDisplay: React.PropTypes.bool, compactDisplay: React.PropTypes.bool,
useMilitaryTime: React.PropTypes.bool.isRequired, useMilitaryTime: React.PropTypes.bool.isRequired,
isFlagged: React.PropTypes.bool isFlagged: React.PropTypes.bool,
status: React.PropTypes.string
}; };

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

@@ -4,6 +4,7 @@
import UserProfile from './user_profile.jsx'; import UserProfile from './user_profile.jsx';
import PostBodyAdditionalContent from 'components/post_view/components/post_body_additional_content.jsx'; import PostBodyAdditionalContent from 'components/post_view/components/post_body_additional_content.jsx';
import FileAttachmentList from './file_attachment_list.jsx'; import FileAttachmentList from './file_attachment_list.jsx';
import ProfilePicture from 'components/profile_picture.jsx';
import ChannelStore from 'stores/channel_store.jsx'; import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx'; import UserStore from 'stores/user_store.jsx';
@@ -40,6 +41,10 @@ export default class RhsRootPost extends React.Component {
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (nextProps.status !== this.props.status) {
return true;
}
if (nextProps.compactDisplay !== this.props.compactDisplay) { if (nextProps.compactDisplay !== this.props.compactDisplay) {
return true; return true;
} }
@@ -276,11 +281,11 @@ export default class RhsRootPost extends React.Component {
} }
let profilePic = ( let profilePic = (
<img <ProfilePicture
className='post-profile-img'
src={PostUtils.getProfilePicSrcForPost(post, timestamp)} src={PostUtils.getProfilePicSrcForPost(post, timestamp)}
height='36' status={this.props.status}
width='36' width='36'
height='36'
/> />
); );
@@ -410,5 +415,6 @@ RhsRootPost.propTypes = {
commentCount: React.PropTypes.number, commentCount: React.PropTypes.number,
compactDisplay: React.PropTypes.bool, compactDisplay: React.PropTypes.bool,
useMilitaryTime: React.PropTypes.bool.isRequired, useMilitaryTime: React.PropTypes.bool.isRequired,
isFlagged: React.PropTypes.bool isFlagged: React.PropTypes.bool,
status: React.PropTypes.string
}; };

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

@@ -55,6 +55,7 @@ export default class RhsThread extends React.Component {
this.onUserChange = this.onUserChange.bind(this); this.onUserChange = this.onUserChange.bind(this);
this.forceUpdateInfo = this.forceUpdateInfo.bind(this); this.forceUpdateInfo = this.forceUpdateInfo.bind(this);
this.onPreferenceChange = this.onPreferenceChange.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this);
this.onStatusChange = this.onStatusChange.bind(this);
this.handleResize = this.handleResize.bind(this); this.handleResize = this.handleResize.bind(this);
const state = this.getPosts(); const state = this.getPosts();
@@ -63,6 +64,7 @@ export default class RhsThread extends React.Component {
state.profiles = JSON.parse(JSON.stringify(UserStore.getProfiles())); state.profiles = JSON.parse(JSON.stringify(UserStore.getProfiles()));
state.compactDisplay = PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT; state.compactDisplay = PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT;
state.flaggedPosts = PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST); state.flaggedPosts = PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST);
state.statuses = Object.assign({}, UserStore.getStatuses());
this.state = state; this.state = state;
} }
@@ -72,6 +74,7 @@ export default class RhsThread extends React.Component {
PostStore.addChangeListener(this.onPostChange); PostStore.addChangeListener(this.onPostChange);
PreferenceStore.addChangeListener(this.onPreferenceChange); PreferenceStore.addChangeListener(this.onPreferenceChange);
UserStore.addChangeListener(this.onUserChange); UserStore.addChangeListener(this.onUserChange);
UserStore.addStatusesChangeListener(this.onStatusChange);
this.scrollToBottom(); this.scrollToBottom();
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
@@ -84,6 +87,7 @@ export default class RhsThread extends React.Component {
PostStore.removeChangeListener(this.onPostChange); PostStore.removeChangeListener(this.onPostChange);
PreferenceStore.removeChangeListener(this.onPreferenceChange); PreferenceStore.removeChangeListener(this.onPreferenceChange);
UserStore.removeChangeListener(this.onUserChange); UserStore.removeChangeListener(this.onUserChange);
UserStore.removeStatusesChangeListener(this.onStatusChange);
window.removeEventListener('resize', this.handleResize); window.removeEventListener('resize', this.handleResize);
@@ -106,6 +110,10 @@ export default class RhsThread extends React.Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
if (!Utils.areObjectsEqual(nextState.statuses, this.state.statuses)) {
return true;
}
if (!Utils.areObjectsEqual(nextState.postsArray, this.state.postsArray)) { if (!Utils.areObjectsEqual(nextState.postsArray, this.state.postsArray)) {
return true; return true;
} }
@@ -168,6 +176,10 @@ export default class RhsThread extends React.Component {
} }
} }
onStatusChange() {
this.setState({statuses: Object.assign({}, UserStore.getStatuses())});
}
getPosts() { getPosts() {
const selected = PostStore.getSelectedPost(); const selected = PostStore.getSelectedPost();
const posts = PostStore.getSelectedPostThread(); const posts = PostStore.getSelectedPostThread();
@@ -251,6 +263,11 @@ export default class RhsThread extends React.Component {
isRootFlagged = this.state.flaggedPosts.get(selected.id) === 'true'; isRootFlagged = this.state.flaggedPosts.get(selected.id) === 'true';
} }
let rootStatus = 'offline';
if (this.state.statuses) {
rootStatus = this.state.statuses[profile.id] || 'offline';
}
return ( return (
<div className='post-right__container'> <div className='post-right__container'>
<FileUploadOverlay overlayType='right'/> <FileUploadOverlay overlayType='right'/>
@@ -281,6 +298,7 @@ export default class RhsThread extends React.Component {
compactDisplay={this.state.compactDisplay} compactDisplay={this.state.compactDisplay}
useMilitaryTime={this.props.useMilitaryTime} useMilitaryTime={this.props.useMilitaryTime}
isFlagged={isRootFlagged} isFlagged={isRootFlagged}
status={rootStatus}
/> />
<div className='post-right-comments-container'> <div className='post-right-comments-container'>
{postsArray.map((comPost) => { {postsArray.map((comPost) => {
@@ -295,6 +313,12 @@ export default class RhsThread extends React.Component {
if (this.state.flaggedPosts) { if (this.state.flaggedPosts) {
isFlagged = this.state.flaggedPosts.get(comPost.id) === 'true'; isFlagged = this.state.flaggedPosts.get(comPost.id) === 'true';
} }
let status = 'offline';
if (this.state.statuses) {
status = this.state.statuses[p.id] || 'offline';
}
return ( return (
<Comment <Comment
ref={comPost.id} ref={comPost.id}
@@ -305,6 +329,7 @@ export default class RhsThread extends React.Component {
compactDisplay={this.state.compactDisplay} compactDisplay={this.state.compactDisplay}
useMilitaryTime={this.props.useMilitaryTime} useMilitaryTime={this.props.useMilitaryTime}
isFlagged={isFlagged} isFlagged={isFlagged}
status={status}
/> />
); );
})} })}

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

@@ -485,8 +485,6 @@
.status-wrapper { .status-wrapper {
display: inline-block;
margin-right: 3px;
position: relative; position: relative;
&:after { &:after {
@@ -517,6 +515,12 @@
.more-modal__row { .more-modal__row {
padding: 5px 10px; padding: 5px 10px;
.status-wrapper {
&:after {
bottom: 0;
}
}
} }
.more-modal__name { .more-modal__name {

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

@@ -865,6 +865,7 @@ body.ios {
height: 32px; height: 32px;
vertical-align: inherit; vertical-align: inherit;
width: 32px; width: 32px;
max-width:none;
} }
} }

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

@@ -330,7 +330,7 @@ class UserStoreClass extends EventEmitter {
} }
var UserStore = new UserStoreClass(); var UserStore = new UserStoreClass();
UserStore.setMaxListeners(15); UserStore.setMaxListeners(16);
UserStore.dispatchToken = AppDispatcher.register((payload) => { UserStore.dispatchToken = AppDispatcher.register((payload) => {
var action = payload.action; var action = payload.action;