From 5a3cbf6086b87c69742ecd1002ca960e4266e5c9 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 11:34:31 -0400 Subject: [PATCH] refactor filterutils --- .../components/DecoratedAppliedFilters.tsx | 2 +- sample-app/src/utils/appliedfilterutils.tsx | 77 +++++++++++++ ...erutils.tsx => displayablefilterutils.tsx} | 25 +---- sample-app/src/utils/filterutils.tsx | 105 +++++------------- 4 files changed, 106 insertions(+), 103 deletions(-) create mode 100644 sample-app/src/utils/appliedfilterutils.tsx rename sample-app/src/utils/{getdisplayablefilterutils.tsx => displayablefilterutils.tsx} (70%) diff --git a/sample-app/src/components/DecoratedAppliedFilters.tsx b/sample-app/src/components/DecoratedAppliedFilters.tsx index fffd095b..7e32195f 100644 --- a/sample-app/src/components/DecoratedAppliedFilters.tsx +++ b/sample-app/src/components/DecoratedAppliedFilters.tsx @@ -2,7 +2,7 @@ import AppliedFilters from "./AppliedFilters"; import { AppliedQueryFilter } from "@yext/answers-core"; import { useAnswersState } from '@yext/answers-headless-react'; import { GroupedFilters } from '../models/groupedFilters'; -import { getGroupedAppliedFilters } from '../utils/filterutils'; +import { getGroupedAppliedFilters } from '../utils/appliedfilterutils'; export interface DecoratedAppliedFiltersConfig { showFieldNames?: boolean, diff --git a/sample-app/src/utils/appliedfilterutils.tsx b/sample-app/src/utils/appliedfilterutils.tsx new file mode 100644 index 00000000..5fa6f76a --- /dev/null +++ b/sample-app/src/utils/appliedfilterutils.tsx @@ -0,0 +1,77 @@ +import { AppliedQueryFilter } from "@yext/answers-core"; +import { FiltersState } from "@yext/answers-headless/lib/esm/models/slices/filters"; +import { DisplayableFilter } from "../models/displayableFilter"; +import { GroupedFilters } from "../models/groupedFilters"; +import { mapArrayToObject } from "./arrayutils"; +import { isDuplicateFilter, flattenFilters } from './filterutils'; +import { + getDisplayableStaticFilters, + getDisplayableAppliedFacets, + getDisplayableNlpFilters +} from "./displayablefilterutils"; + +/** + * Returns a new list of nlp filters with duplicates of other filters and + * filter listed in hiddenFields removed from the given nlp filter list. + */ +function pruneNlpFilters ( + nlpFilters: DisplayableFilter[], + appliedFilters: DisplayableFilter[], + hiddenFields: string[] +): DisplayableFilter[] { + const duplicatesRemoved = nlpFilters.filter(nlpFilter => { + const isDuplicate = appliedFilters.find(appliedFilter => + isDuplicateFilter(nlpFilter.filter, appliedFilter.filter) + ); + return !isDuplicate; + }); + return pruneAppliedFilters(duplicatesRemoved, hiddenFields); +} + +/** + * Returns a new list of applied filters with filter on hiddenFields removed + * from the given applied filter list. + */ +function pruneAppliedFilters( + appliedFilters: DisplayableFilter[], hiddenFields: string[]): DisplayableFilter[] { + return appliedFilters.filter(appliedFilter => { + return !hiddenFields.includes(appliedFilter.filter.fieldId); + }); +} + +/** + * Combine all of the applied filters into a list of GroupedFilters where each contains a label and + * list of filters under that same label or category. + */ +function createGroupedFilters( + appliedFilters: DisplayableFilter[], + nlpFilters: DisplayableFilter[] +): Array { + const getGroupLabel = (filter: DisplayableFilter) => filter.groupLabel; + const allFilters = [...appliedFilters, ...nlpFilters]; + const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); + return Object.keys(groupedFilters).map(label => ({ + label: label, + filters: groupedFilters[label] + })); +} + +/** + * Process all applied filter types (facets, static filters, and nlp filters) by removing + * duplicates and specified hidden fields, and grouped the applied filters into categories. + */ +export function getGroupedAppliedFilters( + appliedFiltersState: FiltersState, + nlpFilters: AppliedQueryFilter[], + hiddenFields: string[] +): Array { + const displayableStaticFilters = getDisplayableStaticFilters(flattenFilters(appliedFiltersState?.static)); + const displayableFacets = getDisplayableAppliedFacets(appliedFiltersState?.facets); + const displayableNlpFilters = getDisplayableNlpFilters(nlpFilters); + + const appliedFilters = [...displayableStaticFilters, ...displayableFacets]; + const prunedAppliedFilters = pruneAppliedFilters(appliedFilters, hiddenFields); + const prunedNlpFilters = pruneNlpFilters (displayableNlpFilters, prunedAppliedFilters, hiddenFields); + + return createGroupedFilters(appliedFilters, prunedNlpFilters); +} \ No newline at end of file diff --git a/sample-app/src/utils/getdisplayablefilterutils.tsx b/sample-app/src/utils/displayablefilterutils.tsx similarity index 70% rename from sample-app/src/utils/getdisplayablefilterutils.tsx rename to sample-app/src/utils/displayablefilterutils.tsx index 5c27c2e5..70005f64 100644 --- a/sample-app/src/utils/getdisplayablefilterutils.tsx +++ b/sample-app/src/utils/displayablefilterutils.tsx @@ -1,27 +1,6 @@ -import { AppliedQueryFilter, Filter, DisplayableFacet, NearFilterValue } from '@yext/answers-core'; +import { AppliedQueryFilter, Filter, DisplayableFacet } from '@yext/answers-core'; import { DisplayableFilter } from '../models/displayableFilter'; - -/** - * Check if the object follows NearFilterValue interface - */ -function isNearFilterValue(obj: Object): obj is NearFilterValue { - return 'radius' in obj && 'lat' in obj && 'long' in obj; -} - -/** - * get a filter's display value or label in string format - */ -function getFilterDisplayValue(filter: Filter): string { - const value = filter.value; - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - return value.toString(); - } - if (isNearFilterValue(value)) { - return `within ${value.radius}m radius`; - } - throw Error('unrecognized filter value type'); -} - +import { getFilterDisplayValue } from './filterutils'; /** * convert a list of facets to DisplayableFilter format with only selected facets returned. diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 6221dd88..9b78d943 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -1,18 +1,31 @@ -import { AppliedQueryFilter, CombinedFilter, Filter } from '@yext/answers-core'; -import { FiltersState } from '@yext/answers-headless/lib/esm/models/slices/filters'; -import { mapArrayToObject } from './arrayutils'; -import { GroupedFilters } from '../models/groupedFilters'; -import { DisplayableFilter } from '../models/displayableFilter'; -import { - getDisplayableAppliedFacets, - getDisplayableStaticFilters, - getDisplayableNlpFilters -} from './getdisplayablefilterutils'; +import { NearFilterValue, CombinedFilter, Filter } from '@yext/answers-core'; + +/** + * Check if the object follows NearFilterValue interface + */ +export function isNearFilterValue(obj: Object): obj is NearFilterValue { + return 'radius' in obj && 'lat' in obj && 'long' in obj; +} + +/** + * get a filter's display value or label in string format + */ +export function getFilterDisplayValue(filter: Filter): string { + const value = filter.value; + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + return value.toString(); + } + if (isNearFilterValue(value)) { + return `within ${value.radius}m radius`; + } + throw Error('unrecognized filter value type'); +} + /** * Check if the object follows CombinedFilter interface */ -function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { +export function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { return 'filters' in obj && 'combinator' in obj; } @@ -20,7 +33,7 @@ function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { * Flatten the given filter, such as if the given filter is of type CombinedFilter * with possible nested layers of Filter objects, into a 1-dimension array of Filter objects */ -function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Array { +export function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Array { let filters: Array = []; if(!filter) { return filters; @@ -36,7 +49,7 @@ function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Arr /** * Returns true if the two given filters are the same */ -function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { +export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { if (thisFilter.fieldId !== otherFilter.fieldId) { return false; } @@ -48,69 +61,3 @@ function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { } return true; } - -/** - * Returns a new list of nlp filters with duplicates of other filters and - * filter listed in hiddenFields removed from the given nlp filter list. - */ -function pruneNlpFilters ( - nlpFilters: DisplayableFilter[], - appliedFilters: DisplayableFilter[], - hiddenFields: string[] -): DisplayableFilter[] { - const duplicatesRemoved = nlpFilters.filter(nlpFilter => { - const isDuplicate = appliedFilters.find(appliedFilter => - isDuplicateFilter(nlpFilter.filter, appliedFilter.filter) - ); - return !isDuplicate; - }); - return pruneAppliedFilters(duplicatesRemoved, hiddenFields); -} - -/** - * Returns a new list of applied filters with filter on hiddenFields removed - * from the given applied filter list. - */ -function pruneAppliedFilters( - appliedFilters: DisplayableFilter[], hiddenFields: string[]): DisplayableFilter[] { - return appliedFilters.filter(appliedFilter => { - return !hiddenFields.includes(appliedFilter.filter.fieldId); - }); -} - -/** - * Combine all of the applied filters into a list of GroupedFilters where each contains a label and - * list of filters under that same label or category. - */ -function createGroupedFilters( - appliedFilters: DisplayableFilter[], - nlpFilters: DisplayableFilter[] -): Array { - const getGroupLabel = (filter: DisplayableFilter) => filter.groupLabel; - const allFilters = [...appliedFilters, ...nlpFilters]; - const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); - return Object.keys(groupedFilters).map(label => ({ - label: label, - filters: groupedFilters[label] - })); -} - -/** - * Process all applied filter types (facets, static filters, and nlp filters) by removing - * duplicates and specified hidden fields, and grouped the applied filters into categories. - */ -export function getGroupedAppliedFilters( - appliedFiltersState: FiltersState, - nlpFilters: AppliedQueryFilter[], - hiddenFields: string[] -): Array { - const displayableStaticFilters = getDisplayableStaticFilters(flattenFilters(appliedFiltersState?.static)); - const displayableFacets = getDisplayableAppliedFacets(appliedFiltersState?.facets); - const displayableNlpFilters = getDisplayableNlpFilters(nlpFilters); - - const appliedFilters = [...displayableStaticFilters, ...displayableFacets]; - const prunedAppliedFilters = pruneAppliedFilters(appliedFilters, hiddenFields); - const prunedNlpFilters = pruneNlpFilters (displayableNlpFilters, prunedAppliedFilters, hiddenFields); - - return createGroupedFilters(appliedFilters, prunedNlpFilters); -}