From ae65a4af6f985d7a98231cb5da47e43f9c9b71dc Mon Sep 17 00:00:00 2001 From: Mattermost Build Date: Thu, 18 Jun 2020 03:26:13 +0200 Subject: [PATCH] MM-13076 Start with store results for at-mention/search autocomplete (#4444) Currently, at-mention and search autocomplete do not render if there is a server request or network problem/outage, because the only data used to populate autocomplete results is a server request. Now, these autocompletes will render initially with user data currently in store, and then re-rendered in place, once the server response completes. Co-authored-by: Amit Uttam --- .../autocomplete/at_mention/at_mention.js | 112 +++++++++++------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/app/components/autocomplete/at_mention/at_mention.js b/app/components/autocomplete/at_mention/at_mention.js index 17da43c07..49a3eb05a 100644 --- a/app/components/autocomplete/at_mention/at_mention.js +++ b/app/components/autocomplete/at_mention/at_mention.js @@ -57,70 +57,46 @@ export default class AtMention extends PureComponent { componentWillReceiveProps(nextProps) { const {inChannel, outChannel, teamMembers, isSearch, matchTerm, requestStatus} = nextProps; - if ((matchTerm !== this.props.matchTerm && matchTerm === null) || this.state.mentionComplete) { - // if the term changes but is null or the mention has been completed we render this component as null + + // Not invoked, render nothing. + if (matchTerm === null) { this.setState({ mentionComplete: false, sections: [], }); - this.props.onResultCountChange(0); - return; - } else if (matchTerm === null) { - // if the terms did not change but is null then we don't need to do anything + } + + if (this.state.mentionComplete) { + // Mention has been completed. Hide autocomplete. + this.setState({ + sections: [], + }); + + this.props.onResultCountChange(0); return; } if (matchTerm !== this.props.matchTerm) { - // if the term changed and we haven't made the request do that first + const sections = this.buildSections(nextProps); + this.setState({ + sections, + }); + + this.props.onResultCountChange(sections.reduce((total, section) => total + section.data.length, 0)); + + // Update user autocomplete list with results of server request const {currentTeamId, currentChannelId} = this.props; const channelId = isSearch ? '' : currentChannelId; this.props.actions.autocompleteUsers(matchTerm, currentTeamId, channelId); return; } + // Server request is complete if (requestStatus !== RequestStatus.STARTED && (inChannel !== this.props.inChannel || outChannel !== this.props.outChannel || teamMembers !== this.props.teamMembers)) { - // if the request is complete and the term is not null we show the autocomplete - const sections = []; - if (isSearch) { - sections.push({ - id: t('mobile.suggestion.members'), - defaultMessage: 'Members', - data: teamMembers, - key: 'teamMembers', - }); - } else { - if (inChannel.length) { - sections.push({ - id: t('suggestion.mention.members'), - defaultMessage: 'Channel Members', - data: inChannel, - key: 'inChannel', - }); - } - - if (this.props.useChannelMentions && this.checkSpecialMentions(matchTerm)) { - sections.push({ - id: t('suggestion.mention.special'), - defaultMessage: 'Special Mentions', - data: this.getSpecialMentions(), - key: 'special', - renderItem: this.renderSpecialMentions, - }); - } - - if (outChannel.length) { - sections.push({ - id: t('suggestion.mention.nonmembers'), - defaultMessage: 'Not in Channel', - data: outChannel, - key: 'outChannel', - }); - } - } - + const sections = this.buildSections(nextProps); this.setState({ sections, }); @@ -129,6 +105,50 @@ export default class AtMention extends PureComponent { } } + buildSections = (props) => { + const {isSearch, inChannel, outChannel, teamMembers, matchTerm} = props; + const sections = []; + + if (isSearch) { + sections.push({ + id: t('mobile.suggestion.members'), + defaultMessage: 'Members', + data: teamMembers, + key: 'teamMembers', + }); + } else { + if (inChannel.length) { + sections.push({ + id: t('suggestion.mention.members'), + defaultMessage: 'Channel Members', + data: inChannel, + key: 'inChannel', + }); + } + + if (this.props.useChannelMentions && this.checkSpecialMentions(matchTerm)) { + sections.push({ + id: t('suggestion.mention.special'), + defaultMessage: 'Special Mentions', + data: this.getSpecialMentions(), + key: 'special', + renderItem: this.renderSpecialMentions, + }); + } + + if (outChannel.length) { + sections.push({ + id: t('suggestion.mention.nonmembers'), + defaultMessage: 'Not in Channel', + data: outChannel, + key: 'outChannel', + }); + } + } + + return sections; + }; + keyExtractor = (item) => { return item.id || item; };