mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
213 lines
6.7 KiB
JavaScript
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
|
|
}; |