Skip to content

Commit

Permalink
feat: ✨ adds filter CANList Pills (Tags) (#2917)
Browse files Browse the repository at this point in the history
* feat: adds CANFilterTags
  • Loading branch information
fpigeonjr authored Oct 11, 2024
1 parent 38e02fc commit 015e650
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 3 deletions.
15 changes: 15 additions & 0 deletions frontend/cypress/e2e/canList.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ describe("CAN List", () => {
// click the button that has text Apply
cy.get("button").contains("Apply").click();

// check that the correct tags are displayed
cy.get("div").contains("Filters Applied:").should("exist");
cy.get("svg[id='filter-tag-activePeriod']").should("exist");
cy.get("svg[id='filter-tag-transfer']").should("exist");
cy.get("svg[id='filter-tag-portfolio']").should("exist");

cy.get("span").contains("1 Year").should("exist");
cy.get("span").contains("Direct").should("exist");
cy.get("span").contains("HMRF").should("exist");

// check that the table is filtered correctly
// table should contain 6 rows

Expand All @@ -77,6 +87,11 @@ describe("CAN List", () => {

// check that the table is filtered correctly
// table should have more than 5 rows
/// check that the correct tags are displayed
cy.get("div").contains("Filters Applied:").should("not.exist");
cy.get("svg[id='filter-tag-activePeriod']").should("not.exist");
cy.get("svg[id='filter-tag-transfer']").should("not.exist");
cy.get("svg[id='filter-tag-portfolio']").should("not.exist");

cy.get("tbody").find("tr").should("have.length.greaterThan", 3);
});
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/UI/FilterTags/FilterTags.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import Tag from "../Tag";
* A filter tags.
* @param {Object} props - The component props.
* @param {Function} props.removeFilter - A function to call to remove a filter/tag.
* @param {Array<string>} props.tagsList - An array of tags to display.
* @returns {React.JSX.Element} - The procurement shop select element.
* @param {string[]} props.tagsList - An array of tags to display.
* @returns {JSX.Element} - The filter tags component. (Pills with an 'x' to remove them)
*/
export const FilterTags = ({ removeFilter, tagsList }) => {
const FilterTag = ({ tag }) => (
Expand Down
89 changes: 89 additions & 0 deletions frontend/src/pages/cans/list/CANFilterTags/CANFilterTags.hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useState, useEffect, useCallback } from "react";
/**
* @typedef {Object} FilterItem
* @property {string} title
*/

/**
* @typedef {Object} Filters
* @property {FilterItem[]} activePeriod
* @property {FilterItem[]} portfolio
* @property {FilterItem[]} transfer
*/

/**
* @typedef {Object} Tag
* @property {string} tagText
* @property {string} filter
*/

/**
* Custom hook for managing tags list
* @param {Filters} filters
* @returns {Tag[]}
*/
export const useTagsList = (filters) => {
const [tagsList, setTagsList] = useState([]);

/**
* @param {keyof Filters} filterKey
* @param {string} filterName
*/
const updateTags = useCallback(
(filterKey, filterName) => {
if (!Array.isArray(filters[filterKey])) return;

const selectedTags = filters[filterKey].map((item) => ({
tagText: item.title,
filter: filterName
}));

setTagsList((prevState) => [...prevState.filter((t) => t.filter !== filterName), ...selectedTags]);
},
[filters]
);

useEffect(() => {
updateTags("activePeriod", "activePeriod");
}, [filters.activePeriod, updateTags]);

useEffect(() => {
updateTags("portfolio", "portfolio");
}, [filters.portfolio, updateTags]);

useEffect(() => {
updateTags("transfer", "transfer");
}, [filters.transfer, updateTags]);

return tagsList;
};

/**
* Removes a filter tag
* @param {Tag} tag - The tag to remove
* @param {function(function(Filters): Filters): void} setFilters - Function to update filters
*/
export const removeFilter = (tag, setFilters) => {
switch (tag.filter) {
case "activePeriod":
setFilters((prevState) => ({
...prevState,
activePeriod: prevState.activePeriod.filter((period) => period.title !== tag.tagText)
}));
break;
case "portfolio":
setFilters((prevState) => ({
...prevState,
portfolio: prevState.portfolio.filter((portfolio) => portfolio.title !== tag.tagText)
}));
break;
case "transfer":
setFilters((prevState) => ({
...prevState,
transfer: prevState.transfer.filter((transfer) => transfer.title !== tag.tagText)
}));
break;
default:
console.warn(`Unknown filter type: ${tag.filter}`);
}
};
35 changes: 35 additions & 0 deletions frontend/src/pages/cans/list/CANFilterTags/CANFilterTags.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import _ from "lodash";
import FilterTags from "../../../../components/UI/FilterTags";
import FilterTagsWrapper from "../../../../components/UI/FilterTags/FilterTagsWrapper";
import { useTagsList, removeFilter } from "./CANFilterTags.hooks";

/**
* A filter tags component.
* @param {Object} props - The component props.
* @param {import('./CANFilterTags.hooks').Filters} props.filters - The current filters.
* @param {() => void} props.setFilters - A function to call to set the filters.
* @returns {JSX.Element|null} The filter tags component or null if no tags.
*/
export const CANFilterTags = ({ filters, setFilters }) => {
const tagsList = useTagsList(filters);

const tagsListByFilter = _.groupBy(tagsList, "filter");
const tagsListByFilterMerged = Object.values(tagsListByFilter)
.flat()
.sort((a, b) => a.tagText.localeCompare(b.tagText));

if (tagsList.length === 0) {
return null;
}

return (
<FilterTagsWrapper>
<FilterTags
removeFilter={(tag) => removeFilter(tag, setFilters)}
tagsList={tagsListByFilterMerged}
/>
</FilterTagsWrapper>
);
};

export default CANFilterTags;
1 change: 1 addition & 0 deletions frontend/src/pages/cans/list/CANFilterTags/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CANFilterTags";
9 changes: 8 additions & 1 deletion frontend/src/pages/cans/list/CanList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import FiscalYear from "../../../components/UI/FiscalYear";
import { setSelectedFiscalYear } from "../../../pages/cans/detail/canDetailSlice";
import ErrorPage from "../../ErrorPage";
import CANFilterButton from "./CANFilterButton";
import { sortAndFilterCANs, getPortfolioOptions } from "./CanList.helpers";
import CANFilterTags from "./CANFilterTags";
import { getPortfolioOptions, sortAndFilterCANs } from "./CanList.helpers";

/**
* Page for the CAN List.
Expand Down Expand Up @@ -79,6 +80,12 @@ const CanList = () => {
/>
}
FYSelect={<CANFiscalYearSelect />}
FilterTags={
<CANFilterTags
filters={filters}
setFilters={setFilters}
/>
}
/>
</App>
)
Expand Down

0 comments on commit 015e650

Please sign in to comment.