From 95d2a4f7f4db0440372f514c2a3f631c627d29b1 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Thu, 21 Oct 2021 18:00:31 -0400 Subject: [PATCH 01/10] Add facets to AppliedFilters J=1656 TEST=manual --- sample-app/src/components/AppliedFilters.tsx | 4 +- .../components/DecoratedAppliedFilters.tsx | 17 +- sample-app/src/models/displayableFilter.ts | 12 +- sample-app/src/utils/filterutils.tsx | 145 +++++++++++++----- 4 files changed, 124 insertions(+), 54 deletions(-) diff --git a/sample-app/src/components/AppliedFilters.tsx b/sample-app/src/components/AppliedFilters.tsx index 6ed0b20f..d182d227 100644 --- a/sample-app/src/components/AppliedFilters.tsx +++ b/sample-app/src/components/AppliedFilters.tsx @@ -40,8 +40,8 @@ function renderFilterLabel(label: string): JSX.Element { function renderAppliedFilters(filters: Array): JSX.Element { const filterElems = filters.map((filter: DisplayableFilter, index: number) => { return ( -
- {filter.filterLabel} +
+ {filter.label} {index < filters.length - 1 && ,}
); diff --git a/sample-app/src/components/DecoratedAppliedFilters.tsx b/sample-app/src/components/DecoratedAppliedFilters.tsx index f6b81879..fffd095b 100644 --- a/sample-app/src/components/DecoratedAppliedFilters.tsx +++ b/sample-app/src/components/DecoratedAppliedFilters.tsx @@ -2,12 +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 { - getAppliedFilters, - pruneAppliedFilters, - pruneNlpFilters, - createGroupedFilters -} from '../utils/filterutils'; +import { getGroupedAppliedFilters } from '../utils/filterutils'; export interface DecoratedAppliedFiltersConfig { showFieldNames?: boolean, @@ -21,13 +16,9 @@ export interface DecoratedAppliedFiltersConfig { * Container component for AppliedFilters */ export function DecoratedAppliedFiltersDisplay(props : DecoratedAppliedFiltersConfig): JSX.Element { - const { hiddenFields = [], appliedQueryFilters, ...otherProps } = props; - let appliedFilters = getAppliedFilters(useAnswersState(state => state.filters)); - appliedFilters = pruneAppliedFilters(appliedFilters, hiddenFields); - let nlpFilters = appliedQueryFilters || []; - nlpFilters = pruneNlpFilters(nlpFilters, appliedFilters, hiddenFields); - const groupedFilters: Array = createGroupedFilters(nlpFilters, appliedFilters); - + const { hiddenFields = [], appliedQueryFilters = [], ...otherProps } = props; + const filterState = useAnswersState(state => state.filters); + const groupedFilters: Array = getGroupedAppliedFilters(filterState, appliedQueryFilters, hiddenFields); return } diff --git a/sample-app/src/models/displayableFilter.ts b/sample-app/src/models/displayableFilter.ts index 29d0fe12..d2e7d917 100644 --- a/sample-app/src/models/displayableFilter.ts +++ b/sample-app/src/models/displayableFilter.ts @@ -1,7 +1,11 @@ -import { Filter } from '@yext/answers-core'; +import { NearFilterValue, Matcher } from '@yext/answers-core'; export interface DisplayableFilter { - filter: Filter, - filterGroupLabel: string, - filterLabel: string + filterType: 'NLP_FILTER' | 'STATIC_FILTER' | 'FACET', + fieldId: string, + matcher: Matcher, + value: string | number | boolean | NearFilterValue, + count?: number, + groupLabel: string, + label: string } diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 6b486cba..5e6d90c4 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -1,20 +1,28 @@ -import { AppliedQueryFilter, CombinedFilter, Filter } from '@yext/answers-core'; +import { AppliedQueryFilter, CombinedFilter, Filter, DisplayableFacet, NearFilterValue } from '@yext/answers-core'; import { FiltersState } from '@yext/answers-headless/lib/esm/models/slices/filters'; import { mapArrayToObject } from '../utils/arrayutils'; import { GroupedFilters } from '../models/groupedFilters'; +import { DisplayableFilter } from '../models/displayableFilter'; /** * Check if the object follows CombinedFilter interface */ -export function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { +function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { return 'filters' in obj && 'combinator' in obj; } +/** + * Check if the object follows NearFilterValue interface + */ +function isNearFilterValue(obj: Object): obj is NearFilterValue { + return 'radius' in obj && 'lat' in obj && 'long' in obj; +} + /** * 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 */ -export function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Array { +function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Array { let filters: Array = []; if(!filter) { return filters; @@ -28,9 +36,9 @@ export function flattenFilters(filter: Filter | CombinedFilter | null | undefine } /** - * Returns true if the two given filters are the same + * Returns true if the two given DisplayableFilters are the same */ -export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { +export function isDuplicateFilter(thisFilter: DisplayableFilter, otherFilter: DisplayableFilter): boolean { if (thisFilter.fieldId !== otherFilter.fieldId) { return false; } @@ -47,24 +55,22 @@ export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): bool * Returns a new list of nlp filters with duplicates of other filters and * filter listed in hiddenFields removed from the given nlp filter list. */ -export function pruneNlpFilters (nlpFilters: AppliedQueryFilter[], appliedFilters: Filter[], - hiddenFields: string[]): AppliedQueryFilter[] { +function pruneNlpFilters (nlpFilters: DisplayableFilter[], appliedFilters: DisplayableFilter[], + hiddenFields: string[]): DisplayableFilter[] { const duplicatesRemoved = nlpFilters.filter(nlpFilter => { const isDuplicate = appliedFilters.find(appliedFilter => - isDuplicateFilter(nlpFilter.filter, appliedFilter) + isDuplicateFilter(nlpFilter, appliedFilter) ); return !isDuplicate; }); - return duplicatesRemoved.filter(nlpFilter => { - return !hiddenFields.includes(nlpFilter.filter.fieldId); - }); + return pruneAppliedFilters(duplicatesRemoved, hiddenFields); } /** * Returns a new list of applied filters with filter on hiddenFields removed - * from the given nlp filter list. + * from the given applied filter list. */ -export function pruneAppliedFilters(appliedFilters: Filter[], hiddenFields: string[]): Filter[] { +function pruneAppliedFilters(appliedFilters: DisplayableFilter[], hiddenFields: string[]): DisplayableFilter[] { return appliedFilters.filter(filter => { return !hiddenFields.includes(filter.fieldId); }); @@ -72,25 +78,12 @@ export function pruneAppliedFilters(appliedFilters: Filter[], hiddenFields: stri /** * 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. All filters will convert to DisplayableFilter format - * where displayValue will be used in the JSX element construction. + * list of filters under that same label or category. */ -export function createGroupedFilters(nlpFilters: AppliedQueryFilter[], appliedFilters: Filter[]): Array { - const getFieldName = (filter: Filter) => filter.fieldId; - const getNlpFieldName = (filter: AppliedQueryFilter) => filter.displayKey; - const getDisplayableAppliedFilter = (filter: Filter) => ({ - filter: filter, - filterGroupLabel: filter.fieldId, - filterLabel: filter.value - }); - const getDisplayableNlpFilter = (filter: AppliedQueryFilter, index: number) => ({ - filter: filter.filter, - filterGroupLabel: filter.displayKey, - filterLabel: filter.displayValue - }); - - let groupedFilters = mapArrayToObject(appliedFilters, getFieldName, getDisplayableAppliedFilter); - groupedFilters = mapArrayToObject(nlpFilters, getNlpFieldName, getDisplayableNlpFilter, groupedFilters); +function createGroupedFilters(appliedFilters: DisplayableFilter[], nlpFilters: DisplayableFilter[]): Array { + const getGroupLabel = (filter: DisplayableFilter) => filter.groupLabel; + const allFilters = appliedFilters.concat(nlpFilters); + const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); return Object.keys(groupedFilters).map(label => ({ label: label, filters: groupedFilters[label] @@ -98,9 +91,91 @@ export function createGroupedFilters(nlpFilters: AppliedQueryFilter[], appliedFi } /** - * Restructure and combine static filters from given FiltersState into a list of Filter objects + * get a filter's display value or label in string format */ -export function getAppliedFilters(appliedFiltersState: FiltersState | undefined): Array { - const appliedStaticFilters = flattenFilters(appliedFiltersState?.static); +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'); +} + +/** + * convert a list of facets to DisplayableFilter format with only selected facets returned. + */ +function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { + let appliedFacets: DisplayableFilter[] = []; + facets?.forEach(facet => { + facet.options.forEach(option => { + if(option.selected) { + appliedFacets.push({ + filterType: 'FACET', + fieldId: facet.fieldId, + matcher: option.matcher, + value: option.value, + groupLabel: facet.displayName, + label: option.displayName, + count: option.count + }); + } + }); + }); + return appliedFacets; +} + +/** + * convert a list of static filters to DisplayableFilter format. + */ +function getDisplayableStaticFilters(filters: Filter[]) { + let appliedStaticFilters: DisplayableFilter[] = []; + filters?.forEach(filter => { + appliedStaticFilters.push({ + filterType: 'STATIC_FILTER', + fieldId: filter.fieldId, + matcher: filter.matcher, + value: filter.value, + groupLabel: filter.fieldId, + label: getFilterDisplayValue(filter), + }); + }); return appliedStaticFilters; -} \ No newline at end of file +} + +/** + * convert a list of nlp filters to DisplayableFilter format. + */ +function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { + let appliedNplFilters: DisplayableFilter[] = []; + filters?.forEach(filter => { + appliedNplFilters.push({ + filterType: 'NLP_FILTER', + fieldId: filter.filter.fieldId, + matcher: filter.filter.matcher, + value: filter.filter.value, + groupLabel: filter.displayKey, + label: filter.displayValue, + }); + }); + return appliedNplFilters; +} + +/** + * 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[]) { + const displayableStaticFilters = getDisplayableStaticFilters(flattenFilters(appliedFiltersState?.static)); + const displayableFacets = getDisplayableAppliedFacets(appliedFiltersState?.facets); + const displayableNlpFilters = getDisplayableNlpFilters(nlpFilters); + + const appliedFilters = displayableStaticFilters.concat(displayableFacets); + const prunedAppliedFilters = pruneAppliedFilters(appliedFilters, hiddenFields); + const prunedNlpFilters = pruneNlpFilters (displayableNlpFilters, prunedAppliedFilters, hiddenFields); + + return createGroupedFilters(appliedFilters, prunedNlpFilters); + +} From 420c5811dcd3573b7d6287966ca931340ccbbc4d Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 09:07:25 -0400 Subject: [PATCH 02/10] renames and removed unused field --- sample-app/src/components/AppliedFilters.tsx | 6 ++-- sample-app/src/models/displayableFilter.ts | 3 +- sample-app/src/utils/filterutils.tsx | 33 ++++++++++---------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/sample-app/src/components/AppliedFilters.tsx b/sample-app/src/components/AppliedFilters.tsx index d182d227..3c6aa77f 100644 --- a/sample-app/src/components/AppliedFilters.tsx +++ b/sample-app/src/components/AppliedFilters.tsx @@ -1,4 +1,4 @@ -import { DisplayableFilter } from '../models/displayableFilter'; +import { DisplayableAppliedFilter } from '../models/displayableFilter'; import { GroupedFilters } from '../models/groupedFilters'; import '../sass/AppliedFilters.scss'; @@ -37,8 +37,8 @@ function renderFilterLabel(label: string): JSX.Element { ); } -function renderAppliedFilters(filters: Array): JSX.Element { - const filterElems = filters.map((filter: DisplayableFilter, index: number) => { +function renderAppliedFilters(filters: Array): JSX.Element { + const filterElems = filters.map((filter: DisplayableAppliedFilter, index: number) => { return (
{filter.label} diff --git a/sample-app/src/models/displayableFilter.ts b/sample-app/src/models/displayableFilter.ts index d2e7d917..802c7bb0 100644 --- a/sample-app/src/models/displayableFilter.ts +++ b/sample-app/src/models/displayableFilter.ts @@ -1,11 +1,10 @@ import { NearFilterValue, Matcher } from '@yext/answers-core'; -export interface DisplayableFilter { +export interface DisplayableAppliedFilter { filterType: 'NLP_FILTER' | 'STATIC_FILTER' | 'FACET', fieldId: string, matcher: Matcher, value: string | number | boolean | NearFilterValue, - count?: number, groupLabel: string, label: string } diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 5e6d90c4..96545e91 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -2,7 +2,7 @@ import { AppliedQueryFilter, CombinedFilter, Filter, DisplayableFacet, NearFilte import { FiltersState } from '@yext/answers-headless/lib/esm/models/slices/filters'; import { mapArrayToObject } from '../utils/arrayutils'; import { GroupedFilters } from '../models/groupedFilters'; -import { DisplayableFilter } from '../models/displayableFilter'; +import { DisplayableAppliedFilter } from '../models/displayableFilter'; /** * Check if the object follows CombinedFilter interface @@ -36,9 +36,9 @@ function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Arr } /** - * Returns true if the two given DisplayableFilters are the same + * Returns true if the two given DisplayableAppliedFilters are the same */ -export function isDuplicateFilter(thisFilter: DisplayableFilter, otherFilter: DisplayableFilter): boolean { +export function isDuplicateFilter(thisFilter: DisplayableAppliedFilter, otherFilter: DisplayableAppliedFilter): boolean { if (thisFilter.fieldId !== otherFilter.fieldId) { return false; } @@ -55,8 +55,8 @@ export function isDuplicateFilter(thisFilter: DisplayableFilter, otherFilter: Di * 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[] { +function pruneNlpFilters (nlpFilters: DisplayableAppliedFilter[], appliedFilters: DisplayableAppliedFilter[], + hiddenFields: string[]): DisplayableAppliedFilter[] { const duplicatesRemoved = nlpFilters.filter(nlpFilter => { const isDuplicate = appliedFilters.find(appliedFilter => isDuplicateFilter(nlpFilter, appliedFilter) @@ -70,7 +70,7 @@ function pruneNlpFilters (nlpFilters: DisplayableFilter[], appliedFilters: Displ * 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[] { +function pruneAppliedFilters(appliedFilters: DisplayableAppliedFilter[], hiddenFields: string[]): DisplayableAppliedFilter[] { return appliedFilters.filter(filter => { return !hiddenFields.includes(filter.fieldId); }); @@ -80,10 +80,10 @@ function pruneAppliedFilters(appliedFilters: DisplayableFilter[], hiddenFields: * 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; +function createGroupedFilters(appliedFilters: DisplayableAppliedFilter[], nlpFilters: DisplayableAppliedFilter[]): Array { + const getGroupLabel = (filter: DisplayableAppliedFilter) => filter.groupLabel; const allFilters = appliedFilters.concat(nlpFilters); - const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); + const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); return Object.keys(groupedFilters).map(label => ({ label: label, filters: groupedFilters[label] @@ -105,10 +105,10 @@ function getFilterDisplayValue(filter: Filter): string { } /** - * convert a list of facets to DisplayableFilter format with only selected facets returned. + * convert a list of facets to DisplayableAppliedFilter format with only selected facets returned. */ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { - let appliedFacets: DisplayableFilter[] = []; + let appliedFacets: DisplayableAppliedFilter[] = []; facets?.forEach(facet => { facet.options.forEach(option => { if(option.selected) { @@ -118,8 +118,7 @@ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { matcher: option.matcher, value: option.value, groupLabel: facet.displayName, - label: option.displayName, - count: option.count + label: option.displayName }); } }); @@ -128,10 +127,10 @@ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { } /** - * convert a list of static filters to DisplayableFilter format. + * convert a list of static filters to DisplayableAppliedFilter format. */ function getDisplayableStaticFilters(filters: Filter[]) { - let appliedStaticFilters: DisplayableFilter[] = []; + let appliedStaticFilters: DisplayableAppliedFilter[] = []; filters?.forEach(filter => { appliedStaticFilters.push({ filterType: 'STATIC_FILTER', @@ -146,10 +145,10 @@ function getDisplayableStaticFilters(filters: Filter[]) { } /** - * convert a list of nlp filters to DisplayableFilter format. + * convert a list of nlp filters to DisplayableAppliedFilter format. */ function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { - let appliedNplFilters: DisplayableFilter[] = []; + let appliedNplFilters: DisplayableAppliedFilter[] = []; filters?.forEach(filter => { appliedNplFilters.push({ filterType: 'NLP_FILTER', From 6a36d40f57edaefbb34fe463d41f26bbd78381c9 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 09:57:35 -0400 Subject: [PATCH 03/10] feedback --- sample-app/src/models/displayableFilter.ts | 6 +-- sample-app/src/utils/filterutils.tsx | 48 +++++++++++++--------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/sample-app/src/models/displayableFilter.ts b/sample-app/src/models/displayableFilter.ts index 802c7bb0..7a898e0c 100644 --- a/sample-app/src/models/displayableFilter.ts +++ b/sample-app/src/models/displayableFilter.ts @@ -1,10 +1,8 @@ -import { NearFilterValue, Matcher } from '@yext/answers-core'; +import { Filter } from '@yext/answers-core'; export interface DisplayableAppliedFilter { filterType: 'NLP_FILTER' | 'STATIC_FILTER' | 'FACET', - fieldId: string, - matcher: Matcher, - value: string | number | boolean | NearFilterValue, + filter: Filter, groupLabel: string, label: string } diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 96545e91..cb60cd9d 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -36,9 +36,9 @@ function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Arr } /** - * Returns true if the two given DisplayableAppliedFilters are the same + * Returns true if the two given filters are the same */ -export function isDuplicateFilter(thisFilter: DisplayableAppliedFilter, otherFilter: DisplayableAppliedFilter): boolean { +export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { if (thisFilter.fieldId !== otherFilter.fieldId) { return false; } @@ -55,11 +55,14 @@ export function isDuplicateFilter(thisFilter: DisplayableAppliedFilter, otherFil * 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: DisplayableAppliedFilter[], appliedFilters: DisplayableAppliedFilter[], - hiddenFields: string[]): DisplayableAppliedFilter[] { +function pruneNlpFilters ( + nlpFilters: DisplayableAppliedFilter[], + appliedFilters: DisplayableAppliedFilter[], + hiddenFields: string[] +): DisplayableAppliedFilter[] { const duplicatesRemoved = nlpFilters.filter(nlpFilter => { const isDuplicate = appliedFilters.find(appliedFilter => - isDuplicateFilter(nlpFilter, appliedFilter) + isDuplicateFilter(nlpFilter.filter, appliedFilter.filter) ); return !isDuplicate; }); @@ -70,9 +73,10 @@ function pruneNlpFilters (nlpFilters: DisplayableAppliedFilter[], appliedFilters * Returns a new list of applied filters with filter on hiddenFields removed * from the given applied filter list. */ -function pruneAppliedFilters(appliedFilters: DisplayableAppliedFilter[], hiddenFields: string[]): DisplayableAppliedFilter[] { - return appliedFilters.filter(filter => { - return !hiddenFields.includes(filter.fieldId); +function pruneAppliedFilters( + appliedFilters: DisplayableAppliedFilter[], hiddenFields: string[]): DisplayableAppliedFilter[] { + return appliedFilters.filter(appliedFilter => { + return !hiddenFields.includes(appliedFilter.filter.fieldId); }); } @@ -80,7 +84,10 @@ function pruneAppliedFilters(appliedFilters: DisplayableAppliedFilter[], hiddenF * 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: DisplayableAppliedFilter[], nlpFilters: DisplayableAppliedFilter[]): Array { +function createGroupedFilters( + appliedFilters: DisplayableAppliedFilter[], + nlpFilters: DisplayableAppliedFilter[] +): Array { const getGroupLabel = (filter: DisplayableAppliedFilter) => filter.groupLabel; const allFilters = appliedFilters.concat(nlpFilters); const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); @@ -114,9 +121,11 @@ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { if(option.selected) { appliedFacets.push({ filterType: 'FACET', - fieldId: facet.fieldId, - matcher: option.matcher, - value: option.value, + filter: { + fieldId: facet.fieldId, + matcher: option.matcher, + value: option.value + }, groupLabel: facet.displayName, label: option.displayName }); @@ -134,9 +143,7 @@ function getDisplayableStaticFilters(filters: Filter[]) { filters?.forEach(filter => { appliedStaticFilters.push({ filterType: 'STATIC_FILTER', - fieldId: filter.fieldId, - matcher: filter.matcher, - value: filter.value, + filter: filter, groupLabel: filter.fieldId, label: getFilterDisplayValue(filter), }); @@ -152,9 +159,7 @@ function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { filters?.forEach(filter => { appliedNplFilters.push({ filterType: 'NLP_FILTER', - fieldId: filter.filter.fieldId, - matcher: filter.filter.matcher, - value: filter.filter.value, + filter: filter.filter, groupLabel: filter.displayKey, label: filter.displayValue, }); @@ -166,7 +171,11 @@ function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { * 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[]) { +export function getGroupedAppliedFilters( + appliedFiltersState: FiltersState, + nlpFilters: AppliedQueryFilter[], + hiddenFields: string[] +) { const displayableStaticFilters = getDisplayableStaticFilters(flattenFilters(appliedFiltersState?.static)); const displayableFacets = getDisplayableAppliedFacets(appliedFiltersState?.facets); const displayableNlpFilters = getDisplayableNlpFilters(nlpFilters); @@ -176,5 +185,4 @@ export function getGroupedAppliedFilters(appliedFiltersState: FiltersState, nlpF const prunedNlpFilters = pruneNlpFilters (displayableNlpFilters, prunedAppliedFilters, hiddenFields); return createGroupedFilters(appliedFilters, prunedNlpFilters); - } From 970641e53d45522acdb63e2fa2f49f661a71c073 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 10:32:01 -0400 Subject: [PATCH 04/10] rename and use spread operator for array concat --- sample-app/src/components/AppliedFilters.tsx | 6 ++-- sample-app/src/models/displayableFilter.ts | 2 +- sample-app/src/utils/filterutils.tsx | 34 ++++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/sample-app/src/components/AppliedFilters.tsx b/sample-app/src/components/AppliedFilters.tsx index 3c6aa77f..d182d227 100644 --- a/sample-app/src/components/AppliedFilters.tsx +++ b/sample-app/src/components/AppliedFilters.tsx @@ -1,4 +1,4 @@ -import { DisplayableAppliedFilter } from '../models/displayableFilter'; +import { DisplayableFilter } from '../models/displayableFilter'; import { GroupedFilters } from '../models/groupedFilters'; import '../sass/AppliedFilters.scss'; @@ -37,8 +37,8 @@ function renderFilterLabel(label: string): JSX.Element { ); } -function renderAppliedFilters(filters: Array): JSX.Element { - const filterElems = filters.map((filter: DisplayableAppliedFilter, index: number) => { +function renderAppliedFilters(filters: Array): JSX.Element { + const filterElems = filters.map((filter: DisplayableFilter, index: number) => { return (
{filter.label} diff --git a/sample-app/src/models/displayableFilter.ts b/sample-app/src/models/displayableFilter.ts index 7a898e0c..8d427fad 100644 --- a/sample-app/src/models/displayableFilter.ts +++ b/sample-app/src/models/displayableFilter.ts @@ -1,6 +1,6 @@ import { Filter } from '@yext/answers-core'; -export interface DisplayableAppliedFilter { +export interface DisplayableFilter { filterType: 'NLP_FILTER' | 'STATIC_FILTER' | 'FACET', filter: Filter, groupLabel: string, diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index cb60cd9d..7009b445 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -2,7 +2,7 @@ import { AppliedQueryFilter, CombinedFilter, Filter, DisplayableFacet, NearFilte import { FiltersState } from '@yext/answers-headless/lib/esm/models/slices/filters'; import { mapArrayToObject } from '../utils/arrayutils'; import { GroupedFilters } from '../models/groupedFilters'; -import { DisplayableAppliedFilter } from '../models/displayableFilter'; +import { DisplayableFilter } from '../models/displayableFilter'; /** * Check if the object follows CombinedFilter interface @@ -56,10 +56,10 @@ export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): bool * filter listed in hiddenFields removed from the given nlp filter list. */ function pruneNlpFilters ( - nlpFilters: DisplayableAppliedFilter[], - appliedFilters: DisplayableAppliedFilter[], + nlpFilters: DisplayableFilter[], + appliedFilters: DisplayableFilter[], hiddenFields: string[] -): DisplayableAppliedFilter[] { +): DisplayableFilter[] { const duplicatesRemoved = nlpFilters.filter(nlpFilter => { const isDuplicate = appliedFilters.find(appliedFilter => isDuplicateFilter(nlpFilter.filter, appliedFilter.filter) @@ -74,7 +74,7 @@ function pruneNlpFilters ( * from the given applied filter list. */ function pruneAppliedFilters( - appliedFilters: DisplayableAppliedFilter[], hiddenFields: string[]): DisplayableAppliedFilter[] { + appliedFilters: DisplayableFilter[], hiddenFields: string[]): DisplayableFilter[] { return appliedFilters.filter(appliedFilter => { return !hiddenFields.includes(appliedFilter.filter.fieldId); }); @@ -85,12 +85,12 @@ function pruneAppliedFilters( * list of filters under that same label or category. */ function createGroupedFilters( - appliedFilters: DisplayableAppliedFilter[], - nlpFilters: DisplayableAppliedFilter[] + appliedFilters: DisplayableFilter[], + nlpFilters: DisplayableFilter[] ): Array { - const getGroupLabel = (filter: DisplayableAppliedFilter) => filter.groupLabel; - const allFilters = appliedFilters.concat(nlpFilters); - const groupedFilters: Record = mapArrayToObject(allFilters, getGroupLabel); + 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] @@ -112,10 +112,10 @@ function getFilterDisplayValue(filter: Filter): string { } /** - * convert a list of facets to DisplayableAppliedFilter format with only selected facets returned. + * convert a list of facets to DisplayableFilter format with only selected facets returned. */ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { - let appliedFacets: DisplayableAppliedFilter[] = []; + let appliedFacets: DisplayableFilter[] = []; facets?.forEach(facet => { facet.options.forEach(option => { if(option.selected) { @@ -136,10 +136,10 @@ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { } /** - * convert a list of static filters to DisplayableAppliedFilter format. + * convert a list of static filters to DisplayableFilter format. */ function getDisplayableStaticFilters(filters: Filter[]) { - let appliedStaticFilters: DisplayableAppliedFilter[] = []; + let appliedStaticFilters: DisplayableFilter[] = []; filters?.forEach(filter => { appliedStaticFilters.push({ filterType: 'STATIC_FILTER', @@ -152,10 +152,10 @@ function getDisplayableStaticFilters(filters: Filter[]) { } /** - * convert a list of nlp filters to DisplayableAppliedFilter format. + * convert a list of nlp filters to DisplayableFilter format. */ function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { - let appliedNplFilters: DisplayableAppliedFilter[] = []; + let appliedNplFilters: DisplayableFilter[] = []; filters?.forEach(filter => { appliedNplFilters.push({ filterType: 'NLP_FILTER', @@ -180,7 +180,7 @@ export function getGroupedAppliedFilters( const displayableFacets = getDisplayableAppliedFacets(appliedFiltersState?.facets); const displayableNlpFilters = getDisplayableNlpFilters(nlpFilters); - const appliedFilters = displayableStaticFilters.concat(displayableFacets); + const appliedFilters = [...displayableStaticFilters, ...displayableFacets]; const prunedAppliedFilters = pruneAppliedFilters(appliedFilters, hiddenFields); const prunedNlpFilters = pruneNlpFilters (displayableNlpFilters, prunedAppliedFilters, hiddenFields); From b79b8d6fb89dbda36d9abea3569360878c60e2f1 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 10:58:57 -0400 Subject: [PATCH 05/10] npl => nlp --- sample-app/src/utils/filterutils.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 7009b445..190e7e7d 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -155,16 +155,16 @@ function getDisplayableStaticFilters(filters: Filter[]) { * convert a list of nlp filters to DisplayableFilter format. */ function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { - let appliedNplFilters: DisplayableFilter[] = []; + let appliedNlpFilters: DisplayableFilter[] = []; filters?.forEach(filter => { - appliedNplFilters.push({ + appliedNlpFilters.push({ filterType: 'NLP_FILTER', filter: filter.filter, groupLabel: filter.displayKey, label: filter.displayValue, }); }); - return appliedNplFilters; + return appliedNlpFilters; } /** From a936792ef173a61b00e93b3d8ba01d932e87ea32 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 11:09:32 -0400 Subject: [PATCH 06/10] return types --- sample-app/src/utils/filterutils.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 190e7e7d..79408cc0 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -114,7 +114,7 @@ function getFilterDisplayValue(filter: Filter): string { /** * convert a list of facets to DisplayableFilter format with only selected facets returned. */ -function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { +function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined): DisplayableFilter[] { let appliedFacets: DisplayableFilter[] = []; facets?.forEach(facet => { facet.options.forEach(option => { @@ -138,7 +138,7 @@ function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined) { /** * convert a list of static filters to DisplayableFilter format. */ -function getDisplayableStaticFilters(filters: Filter[]) { +function getDisplayableStaticFilters(filters: Filter[]): DisplayableFilter[] { let appliedStaticFilters: DisplayableFilter[] = []; filters?.forEach(filter => { appliedStaticFilters.push({ @@ -154,7 +154,7 @@ function getDisplayableStaticFilters(filters: Filter[]) { /** * convert a list of nlp filters to DisplayableFilter format. */ -function getDisplayableNlpFilters(filters: AppliedQueryFilter[]) { +function getDisplayableNlpFilters(filters: AppliedQueryFilter[]): DisplayableFilter[] { let appliedNlpFilters: DisplayableFilter[] = []; filters?.forEach(filter => { appliedNlpFilters.push({ @@ -175,7 +175,7 @@ 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); From 972665053565d43d68da1bf72861193695907bd5 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 11:20:44 -0400 Subject: [PATCH 07/10] refactor filterutils --- .../src/utils/createdisplayablefilter.tsx | 80 +++++++++++++++++ sample-app/src/utils/filterutils.tsx | 88 ++----------------- 2 files changed, 88 insertions(+), 80 deletions(-) create mode 100644 sample-app/src/utils/createdisplayablefilter.tsx diff --git a/sample-app/src/utils/createdisplayablefilter.tsx b/sample-app/src/utils/createdisplayablefilter.tsx new file mode 100644 index 00000000..5c27c2e5 --- /dev/null +++ b/sample-app/src/utils/createdisplayablefilter.tsx @@ -0,0 +1,80 @@ +import { AppliedQueryFilter, Filter, DisplayableFacet, NearFilterValue } 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'); +} + + +/** + * convert a list of facets to DisplayableFilter format with only selected facets returned. + */ +export function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined): DisplayableFilter[] { + let appliedFacets: DisplayableFilter[] = []; + facets?.forEach(facet => { + facet.options.forEach(option => { + if(option.selected) { + appliedFacets.push({ + filterType: 'FACET', + filter: { + fieldId: facet.fieldId, + matcher: option.matcher, + value: option.value + }, + groupLabel: facet.displayName, + label: option.displayName + }); + } + }); + }); + return appliedFacets; +} + +/** + * convert a list of static filters to DisplayableFilter format. + */ +export function getDisplayableStaticFilters(filters: Filter[]): DisplayableFilter[] { + let appliedStaticFilters: DisplayableFilter[] = []; + filters?.forEach(filter => { + appliedStaticFilters.push({ + filterType: 'STATIC_FILTER', + filter: filter, + groupLabel: filter.fieldId, + label: getFilterDisplayValue(filter), + }); + }); + return appliedStaticFilters; +} + +/** + * convert a list of nlp filters to DisplayableFilter format. + */ +export function getDisplayableNlpFilters(filters: AppliedQueryFilter[]): DisplayableFilter[] { + let appliedNlpFilters: DisplayableFilter[] = []; + filters?.forEach(filter => { + appliedNlpFilters.push({ + filterType: 'NLP_FILTER', + filter: filter.filter, + groupLabel: filter.displayKey, + label: filter.displayValue, + }); + }); + return appliedNlpFilters; +} \ No newline at end of file diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 79408cc0..ee09cff9 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -1,8 +1,13 @@ -import { AppliedQueryFilter, CombinedFilter, Filter, DisplayableFacet, NearFilterValue } from '@yext/answers-core'; +import { AppliedQueryFilter, CombinedFilter, Filter } from '@yext/answers-core'; import { FiltersState } from '@yext/answers-headless/lib/esm/models/slices/filters'; -import { mapArrayToObject } from '../utils/arrayutils'; +import { mapArrayToObject } from './arrayutils'; import { GroupedFilters } from '../models/groupedFilters'; import { DisplayableFilter } from '../models/displayableFilter'; +import { + getDisplayableAppliedFacets, + getDisplayableStaticFilters, + getDisplayableNlpFilters +} from './createdisplayablefilter'; /** * Check if the object follows CombinedFilter interface @@ -11,13 +16,6 @@ function isCombinedFilter(obj: Filter | CombinedFilter): obj is CombinedFilter { return 'filters' in obj && 'combinator' in obj; } -/** - * Check if the object follows NearFilterValue interface - */ -function isNearFilterValue(obj: Object): obj is NearFilterValue { - return 'radius' in obj && 'lat' in obj && 'long' in obj; -} - /** * 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 @@ -38,7 +36,7 @@ function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Arr /** * Returns true if the two given filters are the same */ -export function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { +function isDuplicateFilter(thisFilter: Filter, otherFilter: Filter): boolean { if (thisFilter.fieldId !== otherFilter.fieldId) { return false; } @@ -97,76 +95,6 @@ function createGroupedFilters( })); } -/** - * 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'); -} - -/** - * convert a list of facets to DisplayableFilter format with only selected facets returned. - */ -function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined): DisplayableFilter[] { - let appliedFacets: DisplayableFilter[] = []; - facets?.forEach(facet => { - facet.options.forEach(option => { - if(option.selected) { - appliedFacets.push({ - filterType: 'FACET', - filter: { - fieldId: facet.fieldId, - matcher: option.matcher, - value: option.value - }, - groupLabel: facet.displayName, - label: option.displayName - }); - } - }); - }); - return appliedFacets; -} - -/** - * convert a list of static filters to DisplayableFilter format. - */ -function getDisplayableStaticFilters(filters: Filter[]): DisplayableFilter[] { - let appliedStaticFilters: DisplayableFilter[] = []; - filters?.forEach(filter => { - appliedStaticFilters.push({ - filterType: 'STATIC_FILTER', - filter: filter, - groupLabel: filter.fieldId, - label: getFilterDisplayValue(filter), - }); - }); - return appliedStaticFilters; -} - -/** - * convert a list of nlp filters to DisplayableFilter format. - */ -function getDisplayableNlpFilters(filters: AppliedQueryFilter[]): DisplayableFilter[] { - let appliedNlpFilters: DisplayableFilter[] = []; - filters?.forEach(filter => { - appliedNlpFilters.push({ - filterType: 'NLP_FILTER', - filter: filter.filter, - groupLabel: filter.displayKey, - label: filter.displayValue, - }); - }); - return appliedNlpFilters; -} - /** * 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. From 9aa53ed7bd1c9c19aa7e48684298c66e027f8952 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 11:23:27 -0400 Subject: [PATCH 08/10] rename --- sample-app/src/utils/filterutils.tsx | 2 +- ...reatedisplayablefilter.tsx => getdisplayablefilterutils.tsx} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename sample-app/src/utils/{createdisplayablefilter.tsx => getdisplayablefilterutils.tsx} (100%) diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index ee09cff9..6221dd88 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -7,7 +7,7 @@ import { getDisplayableAppliedFacets, getDisplayableStaticFilters, getDisplayableNlpFilters -} from './createdisplayablefilter'; +} from './getdisplayablefilterutils'; /** * Check if the object follows CombinedFilter interface diff --git a/sample-app/src/utils/createdisplayablefilter.tsx b/sample-app/src/utils/getdisplayablefilterutils.tsx similarity index 100% rename from sample-app/src/utils/createdisplayablefilter.tsx rename to sample-app/src/utils/getdisplayablefilterutils.tsx From 5a3cbf6086b87c69742ecd1002ca960e4266e5c9 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 11:34:31 -0400 Subject: [PATCH 09/10] 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); -} From 8903573764e867162670578cecc0542dd958a0e2 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Fri, 22 Oct 2021 12:21:06 -0400 Subject: [PATCH 10/10] nit --- sample-app/src/utils/displayablefilterutils.tsx | 6 +++--- sample-app/src/utils/filterutils.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-app/src/utils/displayablefilterutils.tsx b/sample-app/src/utils/displayablefilterutils.tsx index 70005f64..80286867 100644 --- a/sample-app/src/utils/displayablefilterutils.tsx +++ b/sample-app/src/utils/displayablefilterutils.tsx @@ -3,7 +3,7 @@ import { DisplayableFilter } from '../models/displayableFilter'; import { getFilterDisplayValue } from './filterutils'; /** - * convert a list of facets to DisplayableFilter format with only selected facets returned. + * Convert a list of facets to DisplayableFilter format with only selected facets returned. */ export function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefined): DisplayableFilter[] { let appliedFacets: DisplayableFilter[] = []; @@ -27,7 +27,7 @@ export function getDisplayableAppliedFacets(facets: DisplayableFacet[] | undefin } /** - * convert a list of static filters to DisplayableFilter format. + * Convert a list of static filters to DisplayableFilter format. */ export function getDisplayableStaticFilters(filters: Filter[]): DisplayableFilter[] { let appliedStaticFilters: DisplayableFilter[] = []; @@ -43,7 +43,7 @@ export function getDisplayableStaticFilters(filters: Filter[]): DisplayableFilte } /** - * convert a list of nlp filters to DisplayableFilter format. + * Convert a list of nlp filters to DisplayableFilter format. */ export function getDisplayableNlpFilters(filters: AppliedQueryFilter[]): DisplayableFilter[] { let appliedNlpFilters: DisplayableFilter[] = []; diff --git a/sample-app/src/utils/filterutils.tsx b/sample-app/src/utils/filterutils.tsx index 9b78d943..ba59c9ce 100644 --- a/sample-app/src/utils/filterutils.tsx +++ b/sample-app/src/utils/filterutils.tsx @@ -8,7 +8,7 @@ export function isNearFilterValue(obj: Object): obj is NearFilterValue { } /** - * get a filter's display value or label in string format + * Get a filter's display value or label in string format */ export function getFilterDisplayValue(filter: Filter): string { const value = filter.value;