Skip to content

Commit

Permalink
FilterSearch
Browse files Browse the repository at this point in the history
  • Loading branch information
nmanu1 committed Nov 17, 2021
1 parent 3645f12 commit f703365
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 88 deletions.
40 changes: 31 additions & 9 deletions sample-app/src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ export interface Option {
}

interface Props {
options: Option[],
onClickOption?: (option: Option) => void,
options: {results: Option[], label?: string}[],
onClickOption?: (option: Option, sectionIndex: number, optionIndex: number) => void,
focusedSectionIndex: number | undefined,
focusedOptionIndex: number | undefined,
optionIdPrefix: string,
cssClasses: {
optionContainer: string,
optionSection: string,
sectionLabel: string,
option: string,
focusedOption: string
}
Expand All @@ -23,22 +26,41 @@ interface Props {
export default function Dropdown({
options,
onClickOption = () => {},
focusedSectionIndex,
focusedOptionIndex,
optionIdPrefix,
cssClasses
}: Props): JSX.Element | null {
function renderOption(option: Option, index: number) {
function renderSection(section: {results: Option[], label?: string}, sectionIndex: number) {
return (
<div
className={cssClasses.optionSection}
key={`section-${sectionIndex}`}>
{section.label &&
<div
className={cssClasses.sectionLabel}
key={section.label}>
{section.label}
</div>
}
{section.results.map((option, optionIndex) => renderOption(option, sectionIndex, optionIndex))}
</div>
)
}

function renderOption(option: Option, sectionIndex: number, optionIndex: number) {
const className = classNames(cssClasses.option, {
[cssClasses.focusedOption]: index === focusedOptionIndex
[cssClasses.focusedOption]: sectionIndex === focusedSectionIndex && optionIndex === focusedOptionIndex
})
return (
<div
key={index}
key={`${sectionIndex}-${optionIndex}`}
className={className}
id={`${optionIdPrefix}-${index}`}
onClick={() => onClickOption(option)}>
id={`${optionIdPrefix}-${sectionIndex}-${optionIndex}`}
onClick={() => onClickOption(option, sectionIndex, optionIndex)}>
{option.render()}
</div>)
</div>
)
}

if (options.length < 1) {
Expand All @@ -47,7 +69,7 @@ export default function Dropdown({

return (
<div className={cssClasses.optionContainer}>
{options.map((option, index) => renderOption(option, index))}
{options.map((section, sectionIndex) => renderSection(section, sectionIndex))}
</div>
);
};
68 changes: 33 additions & 35 deletions sample-app/src/components/FilterSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FilterSearchResponse } from "@yext/answers-core";
import { SearchParameterField } from "@yext/answers-core";
import { useCallback, useEffect, useRef, useState } from "react";
import { useRef, useState } from "react";
import { useAnswersActions } from '@yext/answers-headless-react';
import InputDropdown from "./InputDropdown";
import renderWithHighlighting from "./utils/renderWithHighlighting";
Expand All @@ -15,74 +15,72 @@ export interface FilterSearchProps {
screenReaderInstructionsId: string
}


export default function FilterSearch (props: FilterSearchProps): JSX.Element {
const { title, sectioned, searchFields, screenReaderInstructionsId } = props;
const answersActions = useAnswersActions();
const input = useRef<string>('');
const [input, setInput] = useState('');
const [results, updateResults] = useState<FilterSearchResponse|undefined>();
const [, setMessage] = useState( '' );
const requestId = useRef(0);
const responseId = useRef(0);



const executeSearch = useCallback(async () => {
async function executeFilterSearch (inputValue: string) {
const currentId = ++requestId.current;
const results = await answersActions.executeFilterSearch(input.current, sectioned, searchFields);
const results = await answersActions.executeFilterSearch(inputValue, sectioned, searchFields);
if (currentId >= responseId.current) {
responseId.current++;
updateResults(results);
}
}, [answersActions, searchFields, sectioned]);

useEffect(() => {
executeSearch();
}, [executeSearch]);
}

let stuff: Option[] = [];
let options: {results: Option[], label?: string}[] = [];
if (results) {
if(results.sectioned) {
results.sections.forEach(section => {
section.results.forEach(result => {
stuff.push({
value: result.value,
render: () => renderWithHighlighting(result)
});
})
});
} else {
stuff = results.results.map(result => {
return {
results.sections.forEach(section => {
let results: Option[] = [];
section.results.forEach(result => {
results.push({
value: result.value,
render: () => renderWithHighlighting(result)
}
});
});
}
options.push({
results: results,
label: section.label
});
});
}

return (
<div className='FilterSearch'>
<h1>{title}</h1>
<InputDropdown
inputValue={input.current}
inputValue={input}
placeholder='this is filter search...'
screenReaderInstructions={SCREENREADER_INSTRUCTIONS}
screenReaderInstructionsId={screenReaderInstructionsId}
options={stuff}
options={options}
optionIdPrefix='Autocomplete__option'
onSubmit={() => {
answersActions.executeVerticalQuery();
setMessage('enter!');
onlySubmitOnOption={true}
onSubmit={(optionValue, sectionIndex, optionIndex) => {
if (sectionIndex !== undefined && optionIndex !== undefined && results) {
const option = results.sections[sectionIndex].results[optionIndex];
if (option.filter) {
answersActions.setFilterOption({ ...option.filter, selected: true }, 'someFiltersSearchId');
answersActions.executeVerticalQuery();
setMessage('enter!');
}
}
}}
updateInputValue={newInput => {
input.current = newInput;
setInput(newInput);
}}
updateDropdown={() => {
executeSearch();
updateDropdown={(input) => {
executeFilterSearch(input);
}}
cssClasses={{
optionContainer: 'Autocomplete',
optionSection: 'Autocomplete__optionSection',
sectionLabel: 'Autocomplete__sectionLabel',
option: 'Autocomplete__option',
focusedOption: 'Autocomplete__option--focused',
inputElement: 'FilterSearch__input',
Expand Down
Loading

0 comments on commit f703365

Please sign in to comment.