Skip to content

refactor: migrate search screen to the new API #758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 2, 2018

Conversation

machour
Copy link
Member

@machour machour commented Mar 30, 2018

Question Response
Version? v1.4.1
Devices tested? iPhone 7
Bug fix? no
New feature? yes
Includes tests? no
All Tests pass? yes
Related ticket? #751

Description

Refactored the search screen to make use of the new API. Search results are now paginated & cached!

@coveralls
Copy link

coveralls commented Mar 30, 2018

Coverage Status

Coverage decreased (-0.5%) to 42.935% when pulling 458a538 on machour:refactor/search-screen into d77aa82 on gitpoint:master.

Copy link
Member Author

@machour machour left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments to explain normalizrKey

response,
nextPageUrl: this.getNextPageUrl(response),
schema: Schemas.REPO_ARRAY,
normalizrKey: 'items',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first use of normalizrKey.

The API response for this call looks like the following:

{
  total_count: 645354,
  incomplete_results: false,
  items: [
    { /* first repo object */},
    { /* second repo object */},
    ...
  ]
}

We only care for what's inside items, the array of repositories.

normalizrKey tells the dispatch proxy to only treat that property of the JSON, instead of all the JSON.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NICE ⭐️

const SearchTypes = {
REPOS: 0,
USERS: 1,
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

introduced this little enum to make the code more readable


const reposSearchResultsPagination = SEARCH_REPOS[searchQuery] || {
ids: [],
isFetching: false,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contrarily to other PRs, when we're loading this screen, we're not fetching yet, so we set isFetching to false.

@@ -127,19 +161,22 @@ class Search extends Component {
const selectedSearchType =
selectedType !== null ? selectedType : this.state.searchType;

if (query !== '') {
if (query.trim() !== '') {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a trim() here. Currently, if you search for " ", the app will crash!

@@ -127,19 +161,22 @@ class Search extends Component {
const selectedSearchType =
selectedType !== null ? selectedType : this.state.searchType;

if (query !== '') {
if (query.trim() !== '') {
const searchedQuery = query.toLowerCase();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub search is case insensitive. We lowercase the query string in order to avoid having two paginations for nothing (Gitpoint vs gitpoint)

});
if (selectedSearchType === 0) {
searchRepos(query);
this.props.navigation.setParams({ [NAV_QUERY_PARAM]: searchedQuery });
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We save the query string in the navigation, to be able to get it in MapStateToProps and select the corresponding pagination

].nextPageUrl === null
) {
return null;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we conditionally select the good pagination.

I can brake the code to have something less barbaric. This will change anyways when we introduce Code & Wikis search

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, how are you thinking we can simplify this when code & wikis are introduced?

Also, in the meantime, maybe we can simplify the following to something like:

renderFooter = () => {
    const { searchType } = this.state;
    const { reposSearchResultsPagination, usersSearchResultsPagination } = this.props;

    const currResultsPagination = searchType === SearchTypes.REPOS ? reposSearchResultsPagination : usersSearchResultsPagination;

    if (currResultsPagination.nextPageUrl) {
      return (
        <View
          style={{
            paddingVertical: 20,
          }}
        >
          <ActivityIndicator animating size="large" />
        </View>
      );
    }
  };

And another thought (if not know) - maybe we can extract this to a separate component (<LoadingFooter />?) if this logic is duplicated exactly the same in multiple screens?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about having getActiveResultsPagination() & getActiveResults() instead of using ifs everywhere.

And for the refactoring, I was thinking of:

  • a <PaginatedFlatList> which would take a pagination prop and do everything for us.
  • a getPagination() in utils to avoid this chunk of code in mapStateToProps:
  const reposSearchResultsPagination = SEARCH_REPOS[searchQuery] || {
    ids: [],
    isFetching: false,
 }

was just holding off on changing stuff until I got a few PRs merged. I think I'll do that next

? 'searchRepos'
: 'searchUsers'
](query, { loadMore: true })
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same remark as above.

@@ -4,7 +4,6 @@ import { userReducer } from 'user';
import { repositoryReducer } from 'repository';
import { organizationReducer } from 'organization';
import { issueReducer } from 'issue';
import { searchReducer } from 'search';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pew pew pew 🔫

Copy link
Member

@housseindjirdeh housseindjirdeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from one tiny thing, great stuff fam.

I'm excited, you're improving every screen in this app and simplifying our entire Redux store in the same time <3

].nextPageUrl === null
) {
return null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, how are you thinking we can simplify this when code & wikis are introduced?

Also, in the meantime, maybe we can simplify the following to something like:

renderFooter = () => {
    const { searchType } = this.state;
    const { reposSearchResultsPagination, usersSearchResultsPagination } = this.props;

    const currResultsPagination = searchType === SearchTypes.REPOS ? reposSearchResultsPagination : usersSearchResultsPagination;

    if (currResultsPagination.nextPageUrl) {
      return (
        <View
          style={{
            paddingVertical: 20,
          }}
        >
          <ActivityIndicator animating size="large" />
        </View>
      );
    }
  };

And another thought (if not know) - maybe we can extract this to a separate component (<LoadingFooter />?) if this logic is duplicated exactly the same in multiple screens?

@machour
Copy link
Member Author

machour commented Mar 31, 2018

@housseindjirdeh refactoring done, now our render() method doesn't check for the search type anymore (aside for a translation) 🙌

Adding a new search type should be as simple as declaring it in the enum and the switch/case in the new methods.

I also spotted and fixed a minor UI problem, where the Loading list footer was displayed during the first search, resulting in two Loaders being displayed.

@machour
Copy link
Member Author

machour commented Mar 31, 2018

By the way, noticed a bad UX design. Having a single FlatList to handle the various search type results may not be a good idea:

If you search for "react", display results for Repositories and Users, then scroll down on Repositories, when you get back to the Users tab, the list will have been scrolled.

Something to address in another PR.

Copy link
Member

@housseindjirdeh housseindjirdeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So so great, thank you so much 🚀

@housseindjirdeh
Copy link
Member

And aaah I've never caught that before :( That really isn't great behaviour - opened #764 for this

@housseindjirdeh housseindjirdeh merged commit 3991e82 into gitpoint:master Apr 2, 2018
@machour machour deleted the refactor/search-screen branch April 2, 2018 03:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants