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

feat: add filters to Team page #4176

Open
wants to merge 16 commits into
base: ian/team-page-rebuild
Choose a base branch
from

Conversation

RODO94
Copy link
Contributor

@RODO94 RODO94 commented Jan 21, 2025

What does this PR do?

This is tied into the larger epic here: https://trello.com/c/7av8lsVr/3160-epic-as-an-editor-i-want-to-have-a-way-to-organise-my-flows-so-that-i-can-easily-find-what-im-looking-for

This work introduces a Filters component which takes in a governing type and records, and looks to filter this record based on given filterOptions. It was built with further use cases in mind, so I tried to decouple the logic into what is Filter option agnostic, and what should be defined when the filter is used.

By this, I have added the validationFn into the filterOptions defined in the Parent component of <Filters> so you can have control over how we validate when something is true or false. Especially ran into this when status would either be offline | online whereas for serviceType it was defined by hasSendComponent === true | false.

As I was building the component I found it becoming quite long with functions and code, so I separated things out in an iterable FilterColumns component and a selection of helper functions in helpers.ts. It did dawn on me that helpers may be language for testing and it should actually be utils, but I wasn't sure.

Ways to test

Testing of the logic needs to happen in a few places:

  • When you click a filter, the list should not be filtered and there should be no filters in the search params (unless there before)
  • When you click Apply Filters, the list should then be filtered and the filter should appear in the search params
  • To delete a filter, you may delete the Chip, or you can click the checkbox and click Apply filters.
  • The list will filter automatically when you delete a chip, but not when you uncheck a checkbox

Data for applicationType is still to be added and the PR is here: #4169

Warning

Struggling with the way search params are being parsed in my parseStateFromURL() function - they seem to filter but keep resetting the url

return mappedArrayFilters;
};

export const addDisplayNamesToFilters = <T extends object>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This function deals with something similar to the development of SortControl component in this PR:#4137

We have to create a number of ways to name each filter and sometimes they are not very useful for searchParams, UI display, and as keys for objects. A way round this is to slugify the display name when adding the searchParams.

That was it is a nice, followable name in the url that you can connect with the UI and it means for a dev adding it to a new list, you don't need to maintain 3 different types of similar data

Copy link

github-actions bot commented Jan 22, 2025

Pizza

Deployed 094bda6 to https://4176.planx.pizza.

Useful links:

const route = useCurrentRoute();

useEffect(() => {
setOriginalRecords(records);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This maintains a record on mount, I can use for resetting it. I was thinking about how this might change with Search being added, and may have to refine this approach when we bring the two things together. It ultimately though, works well as a component.

@RODO94 RODO94 marked this pull request as ready for review January 22, 2025 15:21
@RODO94 RODO94 requested a review from a team January 22, 2025 17:37
@ianjon3s ianjon3s force-pushed the ian/team-page-rebuild branch from fb24317 to 024214c Compare January 24, 2025 14:41
@RODO94 RODO94 force-pushed the rory/team-page-filters-V02 branch from b30086d to 3034f09 Compare January 24, 2025 14:47
Copy link
Contributor

@DafyddLlyr DafyddLlyr left a comment

Choose a reason for hiding this comment

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

This is a solid start - working largely as expected which is great to see. The generic approach is working well and I can see us easily using this elsewhere which is exactly what I want to be seeing. I think there's some complexity here around state management that we can probably address, but more on that below.

There's a few small comments on code, mostly around types I think.

I'm sure it's on your radar already, but there's currently zero test coverage for the new filter and search functionality - something to follow up on shortly.

I've got a few UI bits of feedback here also -

  1. Both sets of filters are displaying on this branch
    image

  2. A focussed checkbox has a transparent background. Very likely not introduced here, just the first time we're using a checkbox on a non-white background I'd guess.

Screen.Recording.2025-01-27.at.11.49.22.mov
  1. We need to handle 0 results - maybe explain this to the user.

Biggest bit of feedback is around state management and accessibility - this component is without doubt a form!

It accepts user input, has a submit button, meets all the criteria. As such we should treat it as one both in terms of markup (using <form>, <fieldset> elements etc for accessibility) and in terms of state management.

Have a think about this or a crack at it - if we consider this a form, and maybe use formik to be a single source of truth in terms of the form values, how would this simplify our code?

Potentially we could make these changes -

  • addToSearchParams()
  • clearSearchParams()
    • Make these reactive (useEffect()?) based on formik.values
  • clearAllFilters()
    • This just becomes formik.resetForm()
  • removeFilter()
  • removeSelectedFilter()
  • updateFilterState()
    • These would just be a formik.setFieldValue() I guess

All of these functions as you currently have them are manually controlling, validating, and setting our state and we could centralise this in one place.

I would see this as a win in terms of a11y, simplicity, and maintainability. Very happy to talk this change through if you'd like to 👍

editor.planx.uk/src/ui/editor/Filter/Filter.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/ui/editor/Filter/Filter.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/pages/Team.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/pages/Team.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/ui/editor/Filter/Filter.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/ui/editor/Filter/Filter.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/ui/editor/Filter/Filter.tsx Outdated Show resolved Hide resolved
editor.planx.uk/src/ui/editor/SortControl.tsx Outdated Show resolved Hide resolved
</Typography>
</FiltersToggle>
<Box sx={{ display: "flex", gap: 1 }}>
{selectedFilters &&
Copy link
Contributor

Choose a reason for hiding this comment

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

There's some UI inconsistency here (cc @ianjon3s)

  • This list displays the filters currently applied to my list (it's only populated when I hit "Appy...") ✅
  • It does not update as I check and uncheck filters ✅
  • When I remove a tag, a filter becomes unchecked in the form ❌

If this list is meant to describe the filters currently applied, removing a tag should not update the form (but it should update the list - as it currently does).

Open to be challenged here - this felt pretty weird to me, will see if I can cross-reference with a similar component.

Screen.Recording.2025-01-27.at.11.58.49.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure Ian will have better input, but just so I can follow, what is your expected behaviour here? To remove a chip but have the checkbox checked?

Or should you be prompted to apply the filter after clicking delete on a chip?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also would love Ian's thoughts here 😅

The chips are intended to work when the filter accordion is closed, so these should apply immediately when removed - this is expected.

The bit that I found unexpected was that there's just a one-way relationship between the form and chips. I'm not sure how this is best handled when we have one action (remove chip) which is immediate, and another (check/uncheck, and then hit apply) which is not immediate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree the inconsistency isn't ideal. The chips are indeed intended to function when the accordion is closed, so will need to action without the use of a submit button.

Potentially a bit of a refactor, but could we make the filter checkboxes submit on check/uncheck, rather than having a submit button? This would be consistent with the other form fields that will be visible on the page (search input, reorder selects) in that they take immediate action. In terms of accessibility, having an aria-live property on the flows subtitle (Showing 6 services etc) would be necessary for screen readers.

Comment on lines +6 to +20
export enum FlowTagType {
Status = "status",
ApplicationType = "applicationType",
ServiceType = "serviceType",
}

export enum StatusVariant {
Online = "online",
Offline = "offline",
}

const BG_ONLINE = "#D6FFD7";
const BG_OFFLINE = "#EAEAEA";
const BG_APPLICATION_TYPE = "#D6EFFF";
const BG_SERVICE_TYPE = "#FFEABE";
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this needs to be rebased to main as these changes already exist in editor.planx.uk/src/ui/editor/FlowTag/types.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rebased to main, but nothing came up for this. Something to resolve in the Epic PR?

@RODO94 RODO94 force-pushed the rory/team-page-filters-V02 branch from f9bcf42 to d6bd70c Compare January 29, 2025 14:50
@RODO94 RODO94 force-pushed the ian/team-page-rebuild branch from 91a3328 to 6dab004 Compare January 29, 2025 16:29
@RODO94 RODO94 force-pushed the rory/team-page-filters-V02 branch 2 times, most recently from 77aa1eb to d43f596 Compare January 30, 2025 11:35
ianjon3s and others added 12 commits January 30, 2025 11:37
separate styles

switch lodash filter to array.filter

remove filter lodash import

swap out lodash map

switch out lodash map

feat: Add tags to flowCard (#4205)

switch to filter on checkbox and add comments

run prettier on Filter/

remove search and parseUrl dependency array

place filterOptions in static state

run prettier on changed files

status tag shouldAddTag always true
@RODO94 RODO94 force-pushed the rory/team-page-filters-V02 branch from d43f596 to 1e38068 Compare January 30, 2025 11:39
@RODO94 RODO94 force-pushed the ian/team-page-rebuild branch from 6dab004 to 291500b Compare January 30, 2025 11:42
}: FiltersProps<T>) => {
const [expanded, setExpanded] = useState<boolean>(false);
const [filters, setFilters] = useState<Filters<T> | null>(null);
const [optionsToFilter] = useState(filterOptions);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had to memo-ise this or there was an issue with re-rendering from the face it was an array of options, react didn't like it as a dependency. Decided to put it here as a static state variable so I didn't need to memo-ise it in the Team.tsx and I run into the same re-rendering issue if I memo-ise it within Filters.tsx because I still need to add filterOptions as a dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could something similar work for keys in the useSearch hook?

}
}, [filters, setFilteredRecords, records, optionsToFilter]);

useEffect(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a big change since we don't have a button now to update the search params, I have added it to a useEffect() here. I wanted to keep the functions separate so I could conditionally call each one and not have entangle one function with the conditions. It felt longer, but more readable? Happy to take feedback here though

@RODO94 RODO94 requested a review from DafyddLlyr January 30, 2025 11:51
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 this pull request may close these issues.

3 participants