Skip to content

Commit

Permalink
refactor filterutils
Browse files Browse the repository at this point in the history
  • Loading branch information
Yen Truong committed Oct 22, 2021
1 parent 9aa53ed commit 5a3cbf6
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 103 deletions.
2 changes: 1 addition & 1 deletion sample-app/src/components/DecoratedAppliedFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
77 changes: 77 additions & 0 deletions sample-app/src/utils/appliedfilterutils.tsx
Original file line number Diff line number Diff line change
@@ -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<GroupedFilters> {
const getGroupLabel = (filter: DisplayableFilter) => filter.groupLabel;
const allFilters = [...appliedFilters, ...nlpFilters];
const groupedFilters: Record<string, DisplayableFilter[]> = 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<GroupedFilters> {
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);
}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
105 changes: 26 additions & 79 deletions sample-app/src/utils/filterutils.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
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;
}

/**
* 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<Filter> {
export function flattenFilters(filter: Filter | CombinedFilter | null | undefined): Array<Filter> {
let filters: Array<Filter> = [];
if(!filter) {
return filters;
Expand All @@ -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;
}
Expand All @@ -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<GroupedFilters> {
const getGroupLabel = (filter: DisplayableFilter) => filter.groupLabel;
const allFilters = [...appliedFilters, ...nlpFilters];
const groupedFilters: Record<string, DisplayableFilter[]> = 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<GroupedFilters> {
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);
}

0 comments on commit 5a3cbf6

Please sign in to comment.