[MM 13161] Mobile: Add paging to Select Teams screen (#2468)
* Use updated getJoinableTeams function from mattermost-redux * Use onEndReached for infinite scrolling of paginated teams * Add onRefresh * Update Settings screen to expect joinableTeams as array * Fix linter issues * Test that page is updated after getTeams() call * Revert package-lock.json changes * Update mattermost-redux dependency * Update mattermost-redux dependency * Only call getTeams if more can be loaded and only after a previous call has completed * Update snapshot due to prop * Update CustomList to support refreshing as well as option to not render the separator * Use CustomList in SelectTeam
This commit is contained in:
parent
e82146d52f
commit
c72ea6a281
8 changed files with 2994 additions and 2966 deletions
|
|
@ -21,6 +21,8 @@ export default class CustomList extends PureComponent {
|
|||
loading: PropTypes.bool,
|
||||
loadingComponent: PropTypes.element,
|
||||
noResults: PropTypes.element,
|
||||
refreshing: PropTypes.bool,
|
||||
onRefresh: PropTypes.func,
|
||||
onLoadMore: PropTypes.func,
|
||||
onRowPress: PropTypes.func,
|
||||
onRowSelect: PropTypes.func,
|
||||
|
|
@ -30,11 +32,13 @@ export default class CustomList extends PureComponent {
|
|||
]).isRequired,
|
||||
selectable: PropTypes.bool,
|
||||
theme: PropTypes.object.isRequired,
|
||||
shouldRenderSeparator: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
listType: FLATLIST,
|
||||
showNoResults: true,
|
||||
shouldRenderSeparator: true,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -104,7 +108,7 @@ export default class CustomList extends PureComponent {
|
|||
};
|
||||
|
||||
renderFlatList = () => {
|
||||
const {data, extraData, theme} = this.props;
|
||||
const {data, extraData, theme, onRefresh, refreshing} = this.props;
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
return (
|
||||
|
|
@ -122,6 +126,8 @@ export default class CustomList extends PureComponent {
|
|||
maxToRenderPerBatch={INITIAL_BATCH_TO_RENDER + 1}
|
||||
onLayout={this.handleLayout}
|
||||
onScroll={this.handleScroll}
|
||||
onRefresh={onRefresh}
|
||||
refreshing={refreshing}
|
||||
ref={this.setListRef}
|
||||
removeClippedSubviews={true}
|
||||
renderItem={this.renderItem}
|
||||
|
|
@ -185,6 +191,10 @@ export default class CustomList extends PureComponent {
|
|||
};
|
||||
|
||||
renderSeparator = () => {
|
||||
if (!this.props.shouldRenderSeparator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const style = getStyleFromTheme(this.props.theme);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ exports[`MoreChannels should match snapshot 1`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
|
|||
|
|
@ -94,33 +94,52 @@ exports[`SelectTeam should match snapshot for teams 1`] = `
|
|||
}
|
||||
/>
|
||||
</View>
|
||||
<FlatList
|
||||
data={
|
||||
Array [
|
||||
Object {
|
||||
"id": "kemjcpu9bi877yegqjs18ndp4r",
|
||||
"invite_id": "ojsnudhqzbfzpk6e4n6ip1hwae",
|
||||
"name": "test",
|
||||
},
|
||||
]
|
||||
<CustomList
|
||||
data={Array []}
|
||||
extraData={false}
|
||||
listType="flat"
|
||||
loading={false}
|
||||
loadingComponent={
|
||||
<Loading
|
||||
color="grey"
|
||||
size="large"
|
||||
style={Object {}}
|
||||
/>
|
||||
}
|
||||
disableVirtualization={false}
|
||||
horizontal={false}
|
||||
initialNumToRender={10}
|
||||
keyExtractor={[Function]}
|
||||
maxToRenderPerBatch={10}
|
||||
numColumns={1}
|
||||
onEndReachedThreshold={2}
|
||||
onLoadMore={[Function]}
|
||||
onRefresh={[Function]}
|
||||
refreshing={false}
|
||||
renderItem={[Function]}
|
||||
scrollEventThrottle={50}
|
||||
updateCellsBatchingPeriod={50}
|
||||
viewabilityConfig={
|
||||
shouldRenderSeparator={false}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
"viewAreaCoveragePercentThreshold": 3,
|
||||
"waitForInteraction": false,
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
windowSize={21}
|
||||
/>
|
||||
</View>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -10,24 +10,12 @@ import {getTeams, joinTeam} from 'mattermost-redux/actions/teams';
|
|||
import {logout} from 'mattermost-redux/actions/users';
|
||||
import {getJoinableTeams} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
import {getCurrentLocale} from 'app/selectors/i18n';
|
||||
|
||||
import SelectTeam from './select_team.js';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const locale = getCurrentLocale(state);
|
||||
|
||||
function sortTeams(a, b) {
|
||||
const options = {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
};
|
||||
return a.display_name.localeCompare(b.display_name, locale, options);
|
||||
}
|
||||
|
||||
return {
|
||||
teamsRequest: state.requests.teams.getTeams,
|
||||
teams: Object.values(getJoinableTeams(state)).sort(sortTeams),
|
||||
teams: getJoinableTeams(state),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
FlatList,
|
||||
InteractionManager,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
|
|
@ -19,16 +18,14 @@ import FailedNetworkAction from 'app/components/failed_network_action';
|
|||
import FormattedText from 'app/components/formatted_text';
|
||||
import Loading from 'app/components/loading';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import {ListTypes} from 'app/constants';
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme';
|
||||
import {t} from 'app/utils/i18n';
|
||||
import CustomList from 'app/components/custom_list';
|
||||
|
||||
import TeamIcon from 'app/components/team_icon';
|
||||
|
||||
const VIEWABILITY_CONFIG = ListTypes.VISIBILITY_CONFIG_DEFAULTS;
|
||||
|
||||
const TEAMS_PER_PAGE = 200;
|
||||
const TEAMS_PER_PAGE = 50;
|
||||
|
||||
const errorTitle = {
|
||||
id: t('error.team_not_found.title'),
|
||||
|
|
@ -61,8 +58,11 @@ export default class SelectTeam extends PureComponent {
|
|||
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
|
||||
|
||||
this.state = {
|
||||
loading: false,
|
||||
joining: false,
|
||||
teams: null,
|
||||
teams: [],
|
||||
page: 0,
|
||||
refreshing: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +82,12 @@ export default class SelectTeam extends PureComponent {
|
|||
|
||||
getTeams = () => {
|
||||
this.setState({loading: true});
|
||||
this.props.actions.getTeams(0, TEAMS_PER_PAGE).then(() => {
|
||||
this.setState({loading: false});
|
||||
this.buildData(this.props);
|
||||
this.props.actions.getTeams(this.state.page, TEAMS_PER_PAGE).then(() => {
|
||||
this.setState((state) => ({
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
page: state.page + 1,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +169,12 @@ export default class SelectTeam extends PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
onRefresh = () => {
|
||||
this.setState({page: 0, refreshing: true}, () => {
|
||||
this.getTeams();
|
||||
});
|
||||
}
|
||||
|
||||
renderItem = ({item}) => {
|
||||
const {currentUrl, theme} = this.props;
|
||||
const styles = getStyleSheet(theme);
|
||||
|
|
@ -223,7 +232,7 @@ export default class SelectTeam extends PureComponent {
|
|||
const {teams} = this.state;
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
if (this.state.joining || this.state.loading) {
|
||||
if (this.state.joining) {
|
||||
return <Loading/>;
|
||||
}
|
||||
|
||||
|
|
@ -251,11 +260,17 @@ export default class SelectTeam extends PureComponent {
|
|||
</View>
|
||||
<View style={styles.line}/>
|
||||
</View>
|
||||
<FlatList
|
||||
<CustomList
|
||||
data={teams}
|
||||
loading={this.state.loading}
|
||||
loadingComponent={<Loading/>}
|
||||
refreshing={this.state.refreshing}
|
||||
onRefresh={this.onRefresh}
|
||||
onLoadMore={this.getTeams}
|
||||
renderItem={this.renderItem}
|
||||
keyExtractor={(item) => item.id}
|
||||
viewabilityConfig={VIEWABILITY_CONFIG}
|
||||
theme={theme}
|
||||
extraData={this.state.loading}
|
||||
shouldRenderSeparator={false}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,9 @@ describe('SelectTeam', () => {
|
|||
const wrapper = shallow(
|
||||
<SelectTeam {...props}/>,
|
||||
);
|
||||
expect(wrapper.state('page')).toEqual(0);
|
||||
await getTeams();
|
||||
expect(wrapper.state('page')).toEqual(1);
|
||||
wrapper.update();
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ exports[`SelectorScreen should match snapshot for channels 1`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
@ -139,6 +140,7 @@ exports[`SelectorScreen should match snapshot for channels 2`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
@ -232,6 +234,7 @@ exports[`SelectorScreen should match snapshot for explicit options 1`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
@ -318,6 +321,7 @@ exports[`SelectorScreen should match snapshot for searching 1`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
@ -404,6 +408,7 @@ exports[`SelectorScreen should match snapshot for users 1`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
@ -490,6 +495,7 @@ exports[`SelectorScreen should match snapshot for users 2`] = `
|
|||
onLoadMore={[Function]}
|
||||
onRowPress={[Function]}
|
||||
renderItem={[Function]}
|
||||
shouldRenderSeparator={true}
|
||||
showNoResults={true}
|
||||
theme={
|
||||
Object {
|
||||
|
|
|
|||
5821
package-lock.json
generated
5821
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue