Skip to content
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

Add type filtering #40

Closed
Qrtn opened this issue Mar 14, 2021 · 0 comments · Fixed by #42
Closed

Add type filtering #40

Qrtn opened this issue Mar 14, 2021 · 0 comments · Fixed by #42
Assignees

Comments

@Qrtn
Copy link
Collaborator

Qrtn commented Mar 14, 2021

Description

This is it. The big finale to FF's MVP: Type Filtering.

As the user scrolls around on the map, they would like to filter by one or more types. The types that are available to filter directly reflects the types that are currently visible on the map. This means that you can filter in cluster view or location view. It also means that you should GET /types.json each time the map scrolls, and provide the NE/SW lat/lng of the viewport as well; the API will handle giving you the types that have at least one location inside the viewport, as well as their respective counts.

Currently on fallingfruit.org, the website only supports filtering by at most one type. Our app will offer filtering by any number of types. Note that the backend already supports this by taking an array of types; it's just that the current website does not, because UI is tricky.

We have decided to solve this problem with a hierarchal tree select, using this library: react-dropdown-tree-select.

Additionally, types are represented in a hierarchal format. For now, Ethan has chosen to limit the depth of the hierarchy to 1, so assume that for now:

image

The API data gives this tree by specifying a parent_id for each type in GET /types/{id}.json. You will have to build this tree in order to show the hierarchy, because the tree select library expects data in the form of nested objects. (CS 225, anyone?)

image

Right now, it seems that rebuilding the tree after the map scrolls would be slow because parent_id is currently not included in GET /types.json, which means you'd have to GET /types/{id}.json for each type, which fallingfruit.org definitely does not do. @ezwelty, does the current app get the type hierarchy from somewhere? How would we do that as well? See bottom of issue for more details.

Another difference we'll have is the type counts. On fallingfruit.org, the count of the parent type is not the sum of the counts of the child types:

image

Notice how 0 != 2 + 12. It's this way because the count on the parent actually represents the number of locations that are categorized as just "Maple", and not a specific kind of maple. (Let's call them uncategorized maples.) When you click on it, however, it seems that the website does explicitly select the parent and its children (all maples). You'll see that the count also updates to the sum 14.

This is unintuitive, and will also not conceptually work with our tree select, since it's implied that clicking on the parent type will select all the child types. We've decided to solve this by moving the uncategorized maples to a child category "Other" under the general type Maple (see designs below). That "Other" will own the uncategorized count, and the parent type will then have the sum of its children's counts.

Filtering is implemented by sending an array of type IDs to the backend in requests such as GET /locations.json and GET /types.json. We currently have a React context called SearchContext that conveys the viewport of selected search results to MapPage, so it can pan to the searched location. You can take advantage of that context to sync the list of currently filtered type IDs to MapPage as well, so it can include those in its GET /locations.json requests.

We also use React context for sharing the current viewport of the map across components. That's in MapContext's view.

Searching for types

There are tons of types in FF, so it's critical that the user can search for them while filtering. Luckily, the library we're using provides searching built-in. Note these options:

keepTreeOnSearch: By default the tree gets flattened when you're searching, but we want the tree to stay.

Styling

Unlike Reach UI, the library we're using doesn't have as props to specify what components to use for checkboxes, inputs, etc. So we will likely have to replicate styles from our existing UI components, without being able to use the components themselves.

Make sure to reference react-dropdown-tree-select's styling tips, specifically the default class names so that you can select them while styling the outer component.

Relevant Figma designs

Mobile:
image

Desktop:
image

Suggested branch name: type-filtering
Suggested PR title (as would probably be suggested by @code-arman): <some relevant emoji> Add type filtering

Refs #23

Learning objectives

  • Using React context to pass data around. We do this in order to avoid drilling props back and forth in a complicated component hierarchy. This one is pretty valuable, since some kind of structured state management is essential in larger apps. Don't worry, context is pretty easy to use, without a lot of boilerplate. (Remember how we said we wouldn't use Redux in our project? We're still not, but Redux is actually implemented with React contexts.)
  • Data structures and building a tree in JavaScript. Who would have thought?
  • Styling, styling, styling
  • Breaking a complex feature down into simple parts, and implementing each part cleanly

Todo

  • Since this is a big feature, let Jeffrey know about what he can help out on by sometime mid-week, if you think it's necessary
  • Adding a "pressed" prop to IconButton
  • Reorganizing the shared Search component that is currently in desktop and mobile to include the filter button and the tree select component. In that shared component, at most one of [search suggestions, type filtering] should be visible. Note that it's best to just wrap the existing Search component so it doesn't get too long
  • Building the tree with the type hierarchy into a format that the tree select will expect
    • In particular, ensuring that type counts are correct and adding the "Other" category to each parent type
  • Loading types data based on the current viewport of the map, from MapContext
  • Upon changes in the tree select, propagate the correct list of types to the map via SearchContext
    • Being careful with the "Other" category
  • Adding type search to the tree select
  • Style the tree select nodes
  • Style the tree select search input

Useful links

Additional notes

Type Hierarchy

  1. One simple solution is to multiple requests is to include parent_id in GET /types.json so we don't have to make additional GET requests for each type. Rebuilding the actual tree will probably be very fast compared to the overhead of making the network request, so this should work fine for now.
  2. Another solution, which @ezwelty mentioned and requires a lot more work, is to change the API to only return type IDs throughout all requests, and expect the frontend to get all type information ahead of time. This may speed up the API a bit, but requires more investigation.

Virtualization

The library we're using now supports virtualization out of the box, which means that DOM elements are only rendered as they scroll into view. Definitely great to have.

@Qrtn Qrtn self-assigned this Mar 14, 2021
@laurenho025 laurenho025 mentioned this issue Mar 17, 2021
7 tasks
@Qrtn Qrtn removed their assignment Mar 18, 2021
@Qrtn Qrtn self-assigned this Apr 1, 2021
@Qrtn Qrtn mentioned this issue Apr 9, 2021
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants