Files
mattermost/webapp/components/searchable_channel_list.jsx
2017-02-01 16:44:05 +00:00

213 lines
6.7 KiB
JavaScript

// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import LoadingScreen from './loading_screen.jsx';
import * as UserAgent from 'utils/user_agent.jsx';
import $ from 'jquery';
import React from 'react';
import {localizeMessage} from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
import loadingGif from 'images/load.gif';
const NEXT_BUTTON_TIMEOUT_MILLISECONDS = 500;
export default class SearchableChannelList extends React.Component {
constructor(props) {
super(props);
this.createChannelRow = this.createChannelRow.bind(this);
this.nextPage = this.nextPage.bind(this);
this.previousPage = this.previousPage.bind(this);
this.doSearch = this.doSearch.bind(this);
this.nextTimeoutId = 0;
this.state = {
joiningChannel: '',
page: 0,
nextDisabled: false
};
}
componentDidMount() {
// only focus the search box on desktop so that we don't cause the keyboard to open on mobile
if (!UserAgent.isMobile()) {
this.refs.filter.focus();
}
}
componentDidUpdate(prevProps, prevState) {
if (prevState.page !== this.state.page) {
$(this.refs.channelList).scrollTop(0);
}
}
handleJoin(channel) {
this.setState({joiningChannel: channel.id});
this.props.handleJoin(
channel,
() => {
this.setState({joiningChannel: ''});
}
);
}
createChannelRow(channel) {
let joinButton;
if (this.state.joiningChannel === channel.id) {
joinButton = (
<img
className='join-channel-loading-gif'
src={loadingGif}
/>
);
} else {
joinButton = (
<button
onClick={this.handleJoin.bind(this, channel)}
className='btn btn-primary'
>
<FormattedMessage
id='more_channels.join'
defaultMessage='Join'
/>
</button>
);
}
return (
<div
className='more-modal__row'
key={channel.id}
>
<div className='more-modal__details'>
<p className='more-modal__name'>{channel.display_name}</p>
<p className='more-modal__description'>{channel.purpose}</p>
</div>
<div className='more-modal__actions'>
{joinButton}
</div>
</div>
);
}
nextPage(e) {
e.preventDefault();
this.setState({page: this.state.page + 1, nextDisabled: true});
this.nextTimeoutId = setTimeout(() => this.setState({nextDisabled: false}), NEXT_BUTTON_TIMEOUT_MILLISECONDS);
this.props.nextPage(this.state.page + 1);
}
previousPage(e) {
e.preventDefault();
this.setState({page: this.state.page - 1});
}
doSearch() {
const term = this.refs.filter.value;
this.props.search(term);
if (term === '') {
this.setState({page: 0});
}
}
render() {
const channels = this.props.channels;
let listContent;
let nextButton;
let previousButton;
if (channels == null) {
listContent = <LoadingScreen/>;
} else if (channels.length === 0) {
listContent = (
<div className='no-channel-message'>
<p className='primary-message'>
<FormattedMessage
id='more_channels.noMore'
defaultMessage='No more channels to join'
/>
</p>
{this.props.noResultsText}
</div>
);
} else {
const pageStart = this.state.page * this.props.channelsPerPage;
const pageEnd = pageStart + this.props.channelsPerPage;
const channelsToDisplay = this.props.channels.slice(pageStart, pageEnd);
listContent = channelsToDisplay.map(this.createChannelRow);
if (channelsToDisplay.length >= this.props.channelsPerPage) {
nextButton = (
<button
className='btn btn-default filter-control filter-control__next'
onClick={this.nextPage}
disabled={this.state.nextDisabled}
>
<FormattedMessage
id='more_channels.next'
defaultMessage='Next'
/>
</button>
);
}
if (this.state.page > 0) {
previousButton = (
<button
className='btn btn-default filter-control filter-control__prev'
onClick={this.previousPage}
>
<FormattedMessage
id='more_channels.prev'
defaultMessage='Previous'
/>
</button>
);
}
}
return (
<div className='filtered-user-list'>
<div className='filter-row'>
<div className='col-sm-12'>
<input
ref='filter'
className='form-control filter-textbox'
placeholder={localizeMessage('filtered_channels_list.search', 'Search channels')}
onInput={this.doSearch}
/>
</div>
</div>
<div
ref='channelList'
className='more-modal__list'
>
<div>
{listContent}
</div>
</div>
<div className='filter-controls'>
{previousButton}
{nextButton}
</div>
</div>
);
}
}
SearchableChannelList.defaultProps = {
channels: []
};
SearchableChannelList.propTypes = {
channels: React.PropTypes.arrayOf(React.PropTypes.object),
channelsPerPage: React.PropTypes.number,
nextPage: React.PropTypes.func.isRequired,
search: React.PropTypes.func.isRequired,
handleJoin: React.PropTypes.func.isRequired,
noResultsText: React.PropTypes.object
};