From e1547678f3d8cefbdbd76ff3bc2cccef6d0a09aa Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Fri, 29 Sep 2017 11:46:03 -0400 Subject: [PATCH] RN-268 Fixed teams list not always rerendering when team member changes (#970) * RN-268 Fixed teams list not always rerendering when team member changes * Removed unused prop from ChannelDrawer * RN-268 Passed fewer props into TeamsListItem --- .../channel_drawer/teams_list/index.js | 4 +- .../channel_drawer/teams_list/teams_list.js | 151 ++-------------- .../teams_list/teams_list_item/index.js | 24 +++ .../teams_list_item/teams_list_item.js | 171 ++++++++++++++++++ 4 files changed, 211 insertions(+), 139 deletions(-) create mode 100644 app/components/channel_drawer/teams_list/teams_list_item/index.js create mode 100644 app/components/channel_drawer/teams_list/teams_list_item/teams_list_item.js diff --git a/app/components/channel_drawer/teams_list/index.js b/app/components/channel_drawer/teams_list/index.js index b3fafaecf..001793753 100644 --- a/app/components/channel_drawer/teams_list/index.js +++ b/app/components/channel_drawer/teams_list/index.js @@ -5,7 +5,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general'; -import {getCurrentTeamId, getJoinableTeams, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams'; +import {getCurrentTeamId, getJoinableTeams} from 'mattermost-redux/selectors/entities/teams'; import {handleTeamChange} from 'app/actions/views/select_team'; import {getTheme} from 'app/selectors/preferences'; @@ -16,13 +16,11 @@ import TeamsList from './teams_list'; function mapStateToProps(state, ownProps) { return { - canCreateTeams: false, joinableTeams: getJoinableTeams(state), currentTeamId: getCurrentTeamId(state), currentUrl: removeProtocol(getCurrentUrl(state)), teams: getMySortedTeams(state), theme: getTheme(state), - myTeamMembers: getTeamMemberships(state), ...ownProps }; } diff --git a/app/components/channel_drawer/teams_list/teams_list.js b/app/components/channel_drawer/teams_list/teams_list.js index 7f1c39fd2..a8953ee81 100644 --- a/app/components/channel_drawer/teams_list/teams_list.js +++ b/app/components/channel_drawer/teams_list/teams_list.js @@ -11,26 +11,24 @@ import { View } from 'react-native'; import {injectIntl, intlShape} from 'react-intl'; -import IonIcon from 'react-native-vector-icons/Ionicons'; import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; -import Badge from 'app/components/badge'; import FormattedText from 'app/components/formatted_text'; -import {preventDoubleTap} from 'app/utils/tap'; +import {wrapWithPreventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; +import TeamsListItem from './teams_list_item'; + class TeamsList extends PureComponent { static propTypes = { actions: PropTypes.shape({ handleTeamChange: PropTypes.func.isRequired }).isRequired, - canCreateTeams: PropTypes.bool.isRequired, closeChannelDrawer: PropTypes.func.isRequired, currentTeamId: PropTypes.string.isRequired, currentUrl: PropTypes.string.isRequired, intl: intlShape.isRequired, joinableTeams: PropTypes.object.isRequired, - myTeamMembers: PropTypes.object.isRequired, navigator: PropTypes.object.isRequired, teams: PropTypes.array.isRequired, theme: PropTypes.object.isRequired @@ -55,7 +53,7 @@ class TeamsList extends PureComponent { }); }; - goToSelectTeam = () => { + goToSelectTeam = wrapWithPreventDoubleTap(() => { const {currentUrl, intl, navigator, theme} = this.props; navigator.showModal({ @@ -81,79 +79,18 @@ class TeamsList extends PureComponent { theme } }); - }; + }); + + keyExtractor = (team) => { + return team.id; + } renderItem = ({item}) => { - const {currentTeamId, currentUrl, myTeamMembers, theme} = this.props; - const styles = getStyleSheet(theme); - - let current; - let badge; - if (item.id === currentTeamId) { - current = ( - - - - ); - } - - const member = myTeamMembers[item.id]; - - let badgeCount = 0; - if (member.mention_count) { - badgeCount = member.mention_count; - } else if (member.msg_count) { - badgeCount = -1; - } - - if (badgeCount) { - badge = ( - - ); - } - return ( - - preventDoubleTap(this.selectTeam, this, item)} - > - - - - {item.display_name.substr(0, 2).toUpperCase()} - - - - - {item.display_name} - - - {`${currentUrl}/${item.name}`} - - - {current} - - - {badge} - + ); }; @@ -166,7 +103,7 @@ class TeamsList extends PureComponent { moreAction = ( preventDoubleTap(this.goToSelectTeam)} + onPress={this.goToSelectTeam} underlayColor={changeOpacity(theme.sidebarHeaderBg, 0.5)} > item.id} + keyExtractor={this.keyExtractor} viewabilityConfig={{ viewAreaCoveragePercentThreshold: 3, waitForInteraction: false @@ -256,64 +193,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { moreAction: { color: theme.sidebarHeaderTextColor, fontSize: 30 - }, - teamWrapper: { - marginTop: 20 - }, - teamContainer: { - alignItems: 'center', - flex: 1, - flexDirection: 'row', - marginHorizontal: 16 - }, - teamIconContainer: { - alignItems: 'center', - backgroundColor: theme.sidebarText, - borderRadius: 2, - height: 40, - justifyContent: 'center', - width: 40 - }, - teamIcon: { - color: theme.sidebarBg, - fontFamily: 'OpenSans', - fontSize: 18, - fontWeight: '600' - }, - teamNameContainer: { - flex: 1, - flexDirection: 'column', - marginLeft: 10 - }, - teamName: { - color: theme.sidebarText, - fontSize: 18 - }, - teamUrl: { - color: changeOpacity(theme.sidebarText, 0.5), - fontSize: 12 - }, - checkmarkContainer: { - alignItems: 'flex-end' - }, - checkmark: { - color: theme.sidebarText, - fontSize: 20 - }, - badge: { - backgroundColor: theme.mentionBj, - borderColor: theme.sidebarHeaderBg, - borderRadius: 10, - borderWidth: 1, - flexDirection: 'row', - padding: 3, - position: 'absolute', - left: 45, - top: -7.5 - }, - mention: { - color: theme.mentionColor, - fontSize: 10 } }; }); diff --git a/app/components/channel_drawer/teams_list/teams_list_item/index.js b/app/components/channel_drawer/teams_list/teams_list_item/index.js new file mode 100644 index 000000000..c47a0f2b1 --- /dev/null +++ b/app/components/channel_drawer/teams_list/teams_list_item/index.js @@ -0,0 +1,24 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; + +import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general'; +import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; +import {getCurrentTeamId, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams'; + +import {removeProtocol} from 'app/utils/url'; + +import TeamsListItem from './teams_list_item.js'; + +function mapStateToProps(state, ownProps) { + return { + currentTeamId: getCurrentTeamId(state), + currentUrl: removeProtocol(getCurrentUrl(state)), + teamMember: getTeamMemberships(state)[ownProps.team.id], + theme: getTheme(state), + ...ownProps + }; +} + +export default connect(mapStateToProps)(TeamsListItem); diff --git a/app/components/channel_drawer/teams_list/teams_list_item/teams_list_item.js b/app/components/channel_drawer/teams_list/teams_list_item/teams_list_item.js new file mode 100644 index 000000000..c8122f637 --- /dev/null +++ b/app/components/channel_drawer/teams_list/teams_list_item/teams_list_item.js @@ -0,0 +1,171 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; +import PropTypes from 'prop-types'; +import { + Text, + TouchableHighlight, + View +} from 'react-native'; +import IonIcon from 'react-native-vector-icons/Ionicons'; + +import Badge from 'app/components/badge'; +import {wrapWithPreventDoubleTap} from 'app/utils/tap'; +import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; + +export default class TeamsListItem extends React.PureComponent { + static propTypes = { + currentTeamId: PropTypes.string.isRequired, + currentUrl: PropTypes.string.isRequired, + selectTeam: PropTypes.func.isRequired, + team: PropTypes.object.isRequired, + teamMember: PropTypes.object.isRequired, + theme: PropTypes.object.isRequired + }; + + selectTeam = wrapWithPreventDoubleTap(() => { + this.props.selectTeam(this.props.team); + }); + + render() { + const { + currentTeamId, + currentUrl, + team, + teamMember, + theme + } = this.props; + const styles = getStyleSheet(theme); + + let current; + let badge; + if (team.id === currentTeamId) { + current = ( + + + + ); + } + + let badgeCount = 0; + if (teamMember.mention_count) { + badgeCount = teamMember.mention_count; + } else if (teamMember.msg_count) { + badgeCount = -1; + } + + if (badgeCount) { + badge = ( + + ); + } + + return ( + + + + + + {team.display_name.substr(0, 2).toUpperCase()} + + + + + {team.display_name} + + + {`${currentUrl}/${team.name}`} + + + {current} + + + {badge} + + ); + } +} + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + teamWrapper: { + marginTop: 20 + }, + teamContainer: { + alignItems: 'center', + flex: 1, + flexDirection: 'row', + marginHorizontal: 16 + }, + teamIconContainer: { + alignItems: 'center', + backgroundColor: theme.sidebarText, + borderRadius: 2, + height: 40, + justifyContent: 'center', + width: 40 + }, + teamIcon: { + color: theme.sidebarBg, + fontFamily: 'OpenSans', + fontSize: 18, + fontWeight: '600' + }, + teamNameContainer: { + flex: 1, + flexDirection: 'column', + marginLeft: 10 + }, + teamName: { + color: theme.sidebarText, + fontSize: 18 + }, + teamUrl: { + color: changeOpacity(theme.sidebarText, 0.5), + fontSize: 12 + }, + checkmarkContainer: { + alignItems: 'flex-end' + }, + checkmark: { + color: theme.sidebarText, + fontSize: 20 + }, + badge: { + backgroundColor: theme.mentionBj, + borderColor: theme.sidebarHeaderBg, + borderRadius: 10, + borderWidth: 1, + flexDirection: 'row', + padding: 3, + position: 'absolute', + left: 45, + top: -7.5 + }, + mention: { + color: theme.mentionColor, + fontSize: 10 + } + }; +});