From 95a8b4624250fb12e61be5ae29d175cf93d1b3a6 Mon Sep 17 00:00:00 2001 From: enahum Date: Fri, 28 Jul 2017 17:16:25 -0400 Subject: [PATCH] RN-293 Show no resuls found in search for posts (#800) * RN-293 Show no resuls found in search for posts * Update mattermost-redux * remove unnecesary array for style --- app/components/search_bar/search_box.js | 6 +- app/screens/search/index.js | 3 +- app/screens/search/search.js | 84 ++++++++++++++++++------- assets/base/i18n/en.json | 1 + 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/app/components/search_bar/search_box.js b/app/components/search_bar/search_box.js index 967d3aa93..e29d496ef 100644 --- a/app/components/search_bar/search_box.js +++ b/app/components/search_bar/search_box.js @@ -104,7 +104,6 @@ export default class Search extends Component { super(props); this.state = { - keyword: props.value || '', expanded: false }; const {width} = Dimensions.get('window'); @@ -127,6 +126,8 @@ export default class Search extends Component { if (this.props.value !== nextProps.value) { if (nextProps.value) { this.iconDeleteAnimated = new Animated.Value(1); + } else { + this.iconDeleteAnimated = new Animated.Value(0); } } } @@ -202,7 +203,6 @@ export default class Search extends Component { duration: 200 } ).start(); - this.setState({keyword: ''}); if (this.props.onDelete) { this.props.onDelete(); @@ -210,7 +210,7 @@ export default class Search extends Component { }; onCancel = async () => { - this.setState({keyword: '', expanded: false}); + this.setState({expanded: false}); await this.collapseAnimation(true); if (this.props.onCancel) { diff --git a/app/screens/search/index.js b/app/screens/search/index.js index dd941d431..0da996058 100644 --- a/app/screens/search/index.js +++ b/app/screens/search/index.js @@ -7,7 +7,6 @@ import {connect} from 'react-redux'; import {viewChannel, markChannelAsRead} from 'mattermost-redux/actions/channels'; import {getPostsAfter, getPostsBefore, getPostThread, selectPost} from 'mattermost-redux/actions/posts'; import {clearSearch, removeSearchTerms, searchPosts} from 'mattermost-redux/actions/search'; -import {RequestStatus} from 'mattermost-redux/constants'; import {getCurrentChannelId, getMyChannels} from 'mattermost-redux/selectors/entities/channels'; import {getSearchResults} from 'mattermost-redux/selectors/entities/posts'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; @@ -35,7 +34,7 @@ function mapStateToProps(state, ownProps) { posts: getSearchResults(state), recent: recent[currentTeamId] || [], channels: getMyChannels(state), - searching: searchRequest.status === RequestStatus.STARTED + searchingStatus: searchRequest.status }; } diff --git a/app/screens/search/search.js b/app/screens/search/search.js index 69d7bad72..ffe216e0a 100644 --- a/app/screens/search/search.js +++ b/app/screens/search/search.js @@ -15,9 +15,10 @@ import { } from 'react-native'; import IonIcon from 'react-native-vector-icons/Ionicons'; -import {General} from 'mattermost-redux/constants'; +import {General, RequestStatus} from 'mattermost-redux/constants'; import Autocomplete from 'app/components/autocomplete'; +import FormattedText from 'app/components/formatted_text'; import Loading from 'app/components/loading'; import Post from 'app/components/post'; import SectionList from 'app/components/scrollable_section_list'; @@ -33,6 +34,7 @@ const RECENT_LABEL_HEIGHT = 42; const RECENT_SEPARATOR_HEIGHT = 3; const POSTS_PER_PAGE = ViewTypes.POST_VISIBILITY_CHUNK_SIZE; const SEARCHING = 'searching'; +const NO_RESULTS = 'no results'; class Search extends Component { static propTypes = { @@ -54,7 +56,7 @@ class Search extends Component { navigator: PropTypes.object, posts: PropTypes.array, recent: PropTypes.array.isRequired, - searching: PropTypes.bool, + searchingStatus: PropTypes.string, theme: PropTypes.object.isRequired }; @@ -88,10 +90,11 @@ class Search extends Component { } componentDidUpdate() { - const {posts, recent} = this.props; + const {searchingStatus, recent} = this.props; const recentLenght = recent.length; + const shouldScroll = searchingStatus === RequestStatus.SUCCESS || searchingStatus === RequestStatus.STARTED; - if (posts.length && !this.state.isFocused) { + if (shouldScroll && !this.state.isFocused) { setTimeout(() => { this.refs.list.getWrapperRef().getListRef().scrollToOffset({ animated: true, @@ -159,12 +162,13 @@ class Search extends Component { }; handleTextChanged = (value) => { - const {actions, posts} = this.props; + const {actions, searchingStatus} = this.props; this.setState({value}); actions.handleSearchDraftChanged(value); - if (!value && posts.length) { + if (!value && searchingStatus === RequestStatus.SUCCESS) { actions.clearSearch(); + this.scrollToTop(); } }; @@ -181,14 +185,8 @@ class Search extends Component { }; onFocus = () => { - const {posts} = this.props; this.setState({isFocused: true}); - if (posts.length) { - this.refs.list.getWrapperRef().getListRef().scrollToOffset({ - animated: false, - offset: 0 - }); - } + this.scrollToTop(); }; onNavigatorEvent = (event) => { @@ -226,17 +224,17 @@ class Search extends Component { }; renderPost = ({item, index}) => { - if (item.id === SEARCHING) { + const {channels, posts, theme} = this.props; + const style = getStyleFromTheme(theme); + + if (item.id === SEARCHING || item.id === NO_RESULTS) { return ( - + {item.component} ); } - const {channels, posts, theme} = this.props; - const style = getStyleFromTheme(theme); - const channel = channels.find((c) => c.id === item.channel_id); let displayName = ''; @@ -342,6 +340,13 @@ class Search extends Component { ); }; + scrollToTop = () => { + this.refs.list.getWrapperRef().getListRef().scrollToOffset({ + animated: false, + offset: 0 + }); + }; + search = (terms, isOrSearch) => { const {actions, currentTeamId} = this.props; actions.searchPosts(currentTeamId, terms, isOrSearch); @@ -392,7 +397,7 @@ class Search extends Component { navigator, posts, recent, - searching, + searchingStatus, theme } = this.props; @@ -412,13 +417,30 @@ class Search extends Component { } let results; - if (searching) { + if (searchingStatus === RequestStatus.STARTED) { results = [{ id: SEARCHING, - component: + component: ( + + + + ) }]; - } else if (posts.length) { - results = posts; + } else if (searchingStatus === RequestStatus.SUCCESS) { + if (posts.length) { + results = posts; + } else if (this.state.value) { + results = [{ + id: NO_RESULTS, + component: ( + + ) + }]; + } } if (results) { @@ -576,6 +598,22 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { sectionList: { flex: 1, zIndex: -1 + }, + customItem: { + alignItems: 'center', + flex: 1, + justifyContent: 'center' + }, + noResults: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 20, + fontWeight: '400', + marginTop: 65, + textAlign: 'center', + textAlignVertical: 'center' + }, + searching: { + marginTop: 25 } }); }); diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 642fb1504..00af6175c 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -1807,6 +1807,7 @@ "mobile.routes.user_profile": "Profile", "mobile.routes.user_profile.send_message": "Send Message", "mobile.search.jump": "JUMP", + "mobile.search.no_results": "No Results Found", "mobile.select_team.choose": "Your teams:", "mobile.select_team.join_open": "Open teams you can join", "mobile.select_team.no_teams": "There are no available teams for you to join.",