Merge pull request #1174 from florianorben/member-popover

Add styling to channel member popover
Этот коммит содержится в:
Christopher Speller
2015-10-27 08:42:54 -04:00
родитель 5f42451944 bced07a7f4
Коммит 640a7789db
4 изменённых файлов: 215 добавлений и 67 удалений

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

@@ -1,13 +1,7 @@
// 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.
const AsyncClient = require('../utils/async_client.jsx');
const ChannelStore = require('../stores/channel_store.jsx');
const Constants = require('../utils/constants.jsx');
const Client = require('../utils/client.jsx');
const Modal = ReactBootstrap.Modal; const Modal = ReactBootstrap.Modal;
const PreferenceStore = require('../stores/preference_store.jsx');
const TeamStore = require('../stores/team_store.jsx');
const UserStore = require('../stores/user_store.jsx'); const UserStore = require('../stores/user_store.jsx');
const Utils = require('../utils/utils.jsx'); const Utils = require('../utils/utils.jsx');
@@ -70,53 +64,25 @@ export default class MoreDirectChannels extends React.Component {
} }
handleShowDirectChannel(teammate, e) { handleShowDirectChannel(teammate, e) {
e.preventDefault();
if (this.state.loadingDMChannel !== -1) { if (this.state.loadingDMChannel !== -1) {
return; return;
} }
e.preventDefault();
const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), teammate.id);
let channel = ChannelStore.getByName(channelName);
const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, teammate.id, 'true');
AsyncClient.savePreferences([preference]);
if (channel) {
Utils.switchChannel(channel);
this.handleHide();
} else {
this.setState({loadingDMChannel: teammate.id}); this.setState({loadingDMChannel: teammate.id});
Utils.openDirectChannelToUser(
channel = { teammate,
name: channelName, (channel) => {
last_post_at: 0, Utils.switchChannel(channel);
total_msg_count: 0,
type: 'D',
display_name: teammate.username,
teammate_id: teammate.id,
status: UserStore.getStatus(teammate.id)
};
Client.createDirectChannel(
channel,
teammate.id,
(data) => {
this.setState({loadingDMChannel: -1}); this.setState({loadingDMChannel: -1});
AsyncClient.getChannel(data.id);
Utils.switchChannel(data);
this.handleHide(); this.handleHide();
}, },
() => { () => {
this.setState({loadingDMChannel: -1}); this.setState({loadingDMChannel: -1});
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channelName;
} }
); );
} }
}
handleUserChange() { handleUserChange() {
this.setState({users: this.getUsersFromStore()}); this.setState({users: this.getUsersFromStore()});

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

@@ -3,9 +3,23 @@
var UserStore = require('../stores/user_store.jsx'); var UserStore = require('../stores/user_store.jsx');
var Popover = ReactBootstrap.Popover; var Popover = ReactBootstrap.Popover;
var OverlayTrigger = ReactBootstrap.OverlayTrigger; var Overlay = ReactBootstrap.Overlay;
const Utils = require('../utils/utils.jsx');
const ChannelStore = require('../stores/channel_store.jsx');
export default class PopoverListMembers extends React.Component { export default class PopoverListMembers extends React.Component {
constructor(props) {
super(props);
this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
this.closePopover = this.closePopover.bind(this);
}
componentWillMount() {
this.setState({showPopover: false});
}
componentDidMount() { componentDidMount() {
const originalLeave = $.fn.popover.Constructor.prototype.leave; const originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function onLeave(obj) { $.fn.popover.Constructor.prototype.leave = function onLeave(obj) {
@@ -27,12 +41,36 @@ export default class PopoverListMembers extends React.Component {
} }
}; };
} }
handleShowDirectChannel(teammate, e) {
e.preventDefault();
Utils.openDirectChannelToUser(
teammate,
(channel, channelAlreadyExisted) => {
Utils.switchChannel(channel);
if (channelAlreadyExisted) {
this.closePopover();
}
},
() => {
this.closePopover();
}
);
}
closePopover() {
this.setState({showPopover: false});
}
render() { render() {
let popoverHtml = []; let popoverHtml = [];
let count = 0; let count = 0;
let countText = '-'; let countText = '-';
const members = this.props.members; const members = this.props.members;
const teamMembers = UserStore.getProfilesUsernameMap(); const teamMembers = UserStore.getProfilesUsernameMap();
const currentUserId = UserStore.getCurrentId();
const ch = ChannelStore.getCurrent();
if (members && teamMembers) { if (members && teamMembers) {
members.sort((a, b) => { members.sort((a, b) => {
@@ -40,14 +78,75 @@ export default class PopoverListMembers extends React.Component {
}); });
members.forEach((m, i) => { members.forEach((m, i) => {
const details = [];
const fullName = Utils.getFullName(m);
if (fullName) {
details.push(
<span
key={`${m.id}__full-name`}
className='full-name'
>
{fullName}
</span>
);
}
if (m.nickname) {
const separator = fullName ? ' - ' : '';
details.push(
<span
key={`${m.nickname}__nickname`}
>
{separator + m.nickname}
</span>
);
}
let button = '';
if (currentUserId !== m.id && ch.type !== 'D') {
button = (
<button
type='button'
className='btn btn-primary btn-message'
onClick={(e) => this.handleShowDirectChannel(m, e)}
>
{'Message'}
</button>
);
}
if (teamMembers[m.username] && teamMembers[m.username].delete_at <= 0) { if (teamMembers[m.username] && teamMembers[m.username].delete_at <= 0) {
popoverHtml.push( popoverHtml.push(
<div <div
className='text--nowrap' className='text--nowrap'
key={'popover-member-' + i} key={'popover-member-' + i}
> >
<img
className='profile-img pull-left'
width='38'
height='38'
src={`/api/v1/users/${m.id}/image?time=${m.update_at}&${Utils.getSessionIndex()}`}
/>
<div className='pull-left'>
<div
className='more-name'
>
{m.username} {m.username}
</div> </div>
<div
className='more-description'
>
{details}
</div>
</div>
<div
className='pull-right profile-action'
>
{button}
</div>
</div>
); );
count++; count++;
} }
@@ -61,20 +160,12 @@ export default class PopoverListMembers extends React.Component {
} }
return ( return (
<OverlayTrigger <div>
trigger='click' <div
placement='bottom' id='member_popover'
rootClose={true} ref='member_popover_target'
overlay={ onClick={(e) => this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover})}
<Popover
title='Members'
id='member-list-popover'
> >
{popoverHtml}
</Popover>
}
>
<div id='member_popover'>
<div> <div>
{countText} {countText}
<span <span
@@ -83,7 +174,23 @@ export default class PopoverListMembers extends React.Component {
/> />
</div> </div>
</div> </div>
</OverlayTrigger> <Overlay
rootClose={true}
onHide={this.closePopover}
show={this.state.showPopover}
target={() => this.state.popoverTarget}
placement='bottom'
>
<Popover
title='Members'
id='member-list-popover'
>
<div>
{popoverHtml}
</div>
</Popover>
</Overlay>
</div>
); );
} }
} }

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

@@ -8,6 +8,7 @@ var PreferenceStore = require('../stores/preference_store.jsx');
var TeamStore = require('../stores/team_store.jsx'); var TeamStore = require('../stores/team_store.jsx');
var Constants = require('../utils/constants.jsx'); var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes; var ActionTypes = Constants.ActionTypes;
var Client = require('./client.jsx');
var AsyncClient = require('./async_client.jsx'); var AsyncClient = require('./async_client.jsx');
var client = require('./client.jsx'); var client = require('./client.jsx');
var Autolinker = require('autolinker'); var Autolinker = require('autolinker');
@@ -1009,3 +1010,44 @@ export function windowWidth() {
export function windowHeight() { export function windowHeight() {
return $(window).height(); return $(window).height();
} }
export function openDirectChannelToUser(user, successCb, errorCb) {
const channelName = this.getDirectChannelName(UserStore.getCurrentId(), user.id);
let channel = ChannelStore.getByName(channelName);
const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true');
AsyncClient.savePreferences([preference]);
if (channel) {
if ($.isFunction(successCb)) {
successCb(channel, true);
}
} else {
channel = {
name: channelName,
last_post_at: 0,
total_msg_count: 0,
type: 'D',
display_name: user.username,
teammate_id: user.id,
status: UserStore.getStatus(user.id)
};
Client.createDirectChannel(
channel,
user.id,
(data) => {
AsyncClient.getChannel(data.id);
if ($.isFunction(successCb)) {
successCb(data, false);
}
},
() => {
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channelName;
if ($.isFunction(errorCb)) {
errorCb();
}
}
);
}
}

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

@@ -61,3 +61,36 @@
@include opacity(1); @include opacity(1);
} }
} }
#member-list-popover {
max-width: initial;
.popover-content > div {
max-height: 350px;
overflow-y: auto;
overflow-x: hidden;
> div {
border-bottom: 1px solid rgba(51,51,51,0.1);
padding: 8px 8px 8px 15px;
width: 100%;
box-sizing: content-box;
@include clearfix;
.profile-img {
border-radius: 50px;
margin-right: 8px;
}
.more-name {
font-weight: 600;
font-size: 0.95em;
overflow: hidden;
text-overflow: ellipsis;
}
.more-description {
@include opacity(0.7);
}
.profile-action {
margin-left: 8px;
margin-right: 18px;
}
}
}
}