Commit f1524bc5 authored by Sudheer's avatar Sudheer Committed by Carlos Tadeu Panato Junior

MM-12283 Add loader for more_channels modal (#1798)

* MM-12283 Add loader for more_channels modal

  * Add loader when searching for channels

* Fix prop name to channelsRequestStarted

 * Update snapshot

* Remove obsolete snapshot
parent efa293b2
...@@ -6,9 +6,9 @@ import {bindActionCreators} from 'redux'; ...@@ -6,9 +6,9 @@ import {bindActionCreators} from 'redux';
import {createSelector} from 'reselect'; import {createSelector} from 'reselect';
import {getChannels} from 'mattermost-redux/actions/channels'; import {getChannels} from 'mattermost-redux/actions/channels';
import {getOtherChannels} from 'mattermost-redux/selectors/entities/channels'; import {getOtherChannels} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {RequestStatus} from 'mattermost-redux/constants';
import MoreChannels from './more_channels.jsx'; import MoreChannels from './more_channels.jsx';
...@@ -24,6 +24,7 @@ function mapStateToProps(state) { ...@@ -24,6 +24,7 @@ function mapStateToProps(state) {
channels: getNotArchivedOtherChannels(state) || [], channels: getNotArchivedOtherChannels(state) || [],
teamId: team.id, teamId: team.id,
teamName: team.name, teamName: team.name,
channelsRequestStarted: state.requests.channels.getChannels.status === RequestStatus.STARTED,
}; };
} }
......
...@@ -26,6 +26,7 @@ export default class MoreChannels extends React.Component { ...@@ -26,6 +26,7 @@ export default class MoreChannels extends React.Component {
teamName: PropTypes.string.isRequired, teamName: PropTypes.string.isRequired,
onModalDismissed: PropTypes.func, onModalDismissed: PropTypes.func,
handleNewChannel: PropTypes.func, handleNewChannel: PropTypes.func,
channelsRequestStarted: PropTypes.bool,
actions: PropTypes.shape({ actions: PropTypes.shape({
getChannels: PropTypes.func.isRequired, getChannels: PropTypes.func.isRequired,
}).isRequired, }).isRequired,
...@@ -41,6 +42,7 @@ export default class MoreChannels extends React.Component { ...@@ -41,6 +42,7 @@ export default class MoreChannels extends React.Component {
search: false, search: false,
searchedChannels: [], searchedChannels: [],
serverError: null, serverError: null,
searching: false,
}; };
} }
...@@ -98,10 +100,11 @@ export default class MoreChannels extends React.Component { ...@@ -98,10 +100,11 @@ export default class MoreChannels extends React.Component {
if (term === '') { if (term === '') {
this.onChange(true); this.onChange(true);
this.setState({search: false, searchedChannels: []}); this.setState({search: false, searchedChannels: [], searching: false});
this.searchTimeoutId = ''; this.searchTimeoutId = '';
return; return;
} }
this.setState({search: true, searching: true});
const searchTimeoutId = setTimeout( const searchTimeoutId = setTimeout(
() => { () => {
...@@ -122,13 +125,14 @@ export default class MoreChannels extends React.Component { ...@@ -122,13 +125,14 @@ export default class MoreChannels extends React.Component {
} }
setSearchResults = (channels) => { setSearchResults = (channels) => {
this.setState({search: true, searchedChannels: channels.filter((c) => c.delete_at === 0)}); this.setState({searchedChannels: channels.filter((c) => c.delete_at === 0), searching: false});
} }
render() { render() {
const { const {
channels, channels,
teamId, teamId,
channelsRequestStarted,
} = this.props; } = this.props;
const { const {
...@@ -136,6 +140,7 @@ export default class MoreChannels extends React.Component { ...@@ -136,6 +140,7 @@ export default class MoreChannels extends React.Component {
searchedChannels, searchedChannels,
serverError: serverErrorState, serverError: serverErrorState,
show, show,
searching,
} = this.state; } = this.state;
let serverError; let serverError;
...@@ -201,6 +206,7 @@ export default class MoreChannels extends React.Component { ...@@ -201,6 +206,7 @@ export default class MoreChannels extends React.Component {
search={this.search} search={this.search}
handleJoin={this.handleJoin} handleJoin={this.handleJoin}
noResultsText={createChannelHelpText} noResultsText={createChannelHelpText}
loading={search ? searching : channelsRequestStarted}
/> />
{serverError} {serverError}
</Modal.Body> </Modal.Body>
......
...@@ -36,7 +36,7 @@ export default class SearchableChannelList extends React.Component { ...@@ -36,7 +36,7 @@ export default class SearchableChannelList extends React.Component {
componentDidMount() { componentDidMount() {
// only focus the search box on desktop so that we don't cause the keyboard to open on mobile // only focus the search box on desktop so that we don't cause the keyboard to open on mobile
if (!UserAgent.isMobile()) { if (!UserAgent.isMobile() && this.refs.filter) {
this.refs.filter.focus(); this.refs.filter.focus();
} }
} }
...@@ -131,8 +131,8 @@ export default class SearchableChannelList extends React.Component { ...@@ -131,8 +131,8 @@ export default class SearchableChannelList extends React.Component {
let nextButton; let nextButton;
let previousButton; let previousButton;
if (channels == null) { if (this.props.loading && channels.length === 0) {
listContent = <LoadingScreen/>; listContent = <LoadingScreen style={{marginTop: '50%'}}/>;
} else if (channels.length === 0) { } else if (channels.length === 0) {
listContent = ( listContent = (
<div className='no-channel-message'> <div className='no-channel-message'>
...@@ -224,4 +224,5 @@ SearchableChannelList.propTypes = { ...@@ -224,4 +224,5 @@ SearchableChannelList.propTypes = {
search: PropTypes.func.isRequired, search: PropTypes.func.isRequired,
handleJoin: PropTypes.func.isRequired, handleJoin: PropTypes.func.isRequired,
noResultsText: PropTypes.object, noResultsText: PropTypes.object,
loading: PropTypes.bool,
}; };
...@@ -81,6 +81,7 @@ exports[`components/MoreChannels should match snapshot and state 1`] = ` ...@@ -81,6 +81,7 @@ exports[`components/MoreChannels should match snapshot and state 1`] = `
channelsPerPage={50} channelsPerPage={50}
handleJoin={[Function]} handleJoin={[Function]}
isSearch={false} isSearch={false}
loading={false}
nextPage={[Function]} nextPage={[Function]}
noResultsText={ noResultsText={
<Connect(TeamPermissionGate) <Connect(TeamPermissionGate)
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/SearchableChannelList should match init snapshot 1`] = `
<div
className="filtered-user-list"
>
<div
className="filter-row"
>
<div
className="col-sm-12"
>
<QuickInput
className="form-control filter-textbox"
delayInputUpdate={false}
id="searchChannelsTextbox"
onInput={[Function]}
placeholder="Search channels"
value=""
/>
</div>
</div>
<div
className="more-modal__list"
>
<div>
<LoadingScreen
position="relative"
style={
Object {
"marginTop": "50%",
}
}
/>
</div>
</div>
<div
className="filter-controls"
/>
</div>
`;
...@@ -5,12 +5,14 @@ import React from 'react'; ...@@ -5,12 +5,14 @@ import React from 'react';
import {shallow} from 'enzyme'; import {shallow} from 'enzyme';
import MoreChannels from 'components/more_channels/more_channels.jsx'; import MoreChannels from 'components/more_channels/more_channels.jsx';
import SearchableChannelList from 'components/searchable_channel_list.jsx';
describe('components/MoreChannels', () => { describe('components/MoreChannels', () => {
const baseProps = { const baseProps = {
channels: [{id: 'channel_id_1', delete_at: 0}], channels: [{id: 'channel_id_1', delete_at: 0}],
teamId: 'team_id', teamId: 'team_id',
teamName: 'team_name', teamName: 'team_name',
channelsRequestStarted: false,
onModalDismissed: () => {}, // eslint-disable-line no-empty-function onModalDismissed: () => {}, // eslint-disable-line no-empty-function
handleNewChannel: () => {}, // eslint-disable-line no-empty-function handleNewChannel: () => {}, // eslint-disable-line no-empty-function
actions: { actions: {
...@@ -29,6 +31,7 @@ describe('components/MoreChannels', () => { ...@@ -29,6 +31,7 @@ describe('components/MoreChannels', () => {
expect(wrapper.state('show')).toEqual(true); expect(wrapper.state('show')).toEqual(true);
expect(wrapper.state('search')).toEqual(false); expect(wrapper.state('search')).toEqual(false);
expect(wrapper.state('serverError')).toBeNull(); expect(wrapper.state('serverError')).toBeNull();
expect(wrapper.state('searching')).toEqual(false);
// on componentDidMount // on componentDidMount
expect(actions.getChannels).toHaveBeenCalledTimes(1); expect(actions.getChannels).toHaveBeenCalledTimes(1);
...@@ -80,4 +83,14 @@ describe('components/MoreChannels', () => { ...@@ -80,4 +83,14 @@ describe('components/MoreChannels', () => {
expect(actions.getChannels).toHaveBeenCalledTimes(2); expect(actions.getChannels).toHaveBeenCalledTimes(2);
expect(actions.getChannels).toHaveBeenCalledWith(props.teamId, 2, 50); expect(actions.getChannels).toHaveBeenCalledWith(props.teamId, 2, 50);
}); });
test('should have loading prop true when searching state is true', () => {
const wrapper = shallow(
<MoreChannels {...baseProps}/>
);
wrapper.setState({search: true, searching: true});
const searchList = wrapper.find(SearchableChannelList);
expect(searchList.props().loading).toEqual(true);
});
}); });
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {shallow} from 'enzyme';
import SearchableChannelList from 'components/searchable_channel_list.jsx';
describe('components/SearchableChannelList', () => {
const baseProps = {
channels: [],
isSearch: false,
channelsPerPage: 10,
nextPage: () => {}, // eslint-disable-line no-empty-function
search: () => {}, // eslint-disable-line no-empty-function
handleJoin: () => {}, // eslint-disable-line no-empty-function
loading: true,
};
test('should match init snapshot', () => {
const wrapper = shallow(
<SearchableChannelList {...baseProps}/>
);
expect(wrapper).toMatchSnapshot();
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment