[question][feat] add autocomplete to filters

pull/411/head
Jeff Sieu 3 years ago
parent 58ee0ba349
commit d9f126af05

@ -1,8 +1,11 @@
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { CheckboxInput, Collapsible, RadioList, TextInput } from '@tih/ui';
import { useMemo } from 'react';
import type { UseFormRegisterReturn } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { CheckboxInput, Collapsible, RadioList } from '@tih/ui';
export type FilterOption<V extends string = string> = {
checked: boolean;
id: string;
label: string;
value: V;
};
@ -30,37 +33,66 @@ export type FilterSectionProps<FilterOptions extends Array<FilterOption>> =
options: FilterOptions;
} & (
| {
searchPlaceholder: string;
renderInput: (props: {
field: UseFormRegisterReturn<'search'>;
onOptionChange: FilterSectionType<FilterOptions>['onOptionChange'];
options: FilterOptions;
}) => React.ReactNode;
showAll?: never;
}
| {
searchPlaceholder?: never;
renderInput?: never;
showAll: true;
}
);
export type FilterSectionFormData = {
search: string;
};
export default function FilterSection<
FilterOptions extends Array<FilterOption>,
>({
label,
options,
searchPlaceholder,
showAll,
onOptionChange,
isSingleSelect,
renderInput,
}: FilterSectionProps<FilterOptions>) {
const { register, reset } = useForm<FilterSectionFormData>();
const registerSearch = register('search');
const field: UseFormRegisterReturn<'search'> = {
...registerSearch,
onChange: async (event) => {
await registerSearch.onChange(event);
reset();
},
};
const autocompleteOptions = useMemo(() => {
return options.filter((option) => !option.checked) as FilterOptions;
}, [options]);
return (
<div className="mx-2">
<Collapsible defaultOpen={true} label={label}>
<div className="-mx-2 flex flex-col items-stretch gap-2">
{!showAll && (
<TextInput
isLabelHidden={true}
label={label}
placeholder={searchPlaceholder}
startAddOn={MagnifyingGlassIcon}
startAddOnType="icon"
/>
<div className="z-10">
{renderInput({
field,
onOptionChange: async (
optionValue: FilterOptions[number]['value'],
) => {
reset();
return onOptionChange(optionValue, true);
},
options: autocompleteOptions,
})}
</div>
)}
{isSingleSelect ? (
<div className="px-1.5">
@ -81,7 +113,9 @@ export default function FilterSection<
</div>
) : (
<div className="px-1.5">
{options.map((option) => (
{options
.filter((option) => showAll || option.checked)
.map((option) => (
<CheckboxInput
key={option.value}
label={option.label}

@ -3,7 +3,7 @@ import Router, { useRouter } from 'next/router';
import { useEffect, useMemo, useState } from 'react';
import { NoSymbolIcon } from '@heroicons/react/24/outline';
import type { QuestionsQuestionType } from '@prisma/client';
import { SlideOut } from '@tih/ui';
import { SlideOut, Typeahead } from '@tih/ui';
import QuestionOverviewCard from '~/components/questions/card/QuestionOverviewCard';
import ContributeQuestionCard from '~/components/questions/ContributeQuestionCard';
@ -188,7 +188,18 @@ export default function QuestionsHomePage() {
<FilterSection
label="Company"
options={companyFilterOptions}
searchPlaceholder="Add company filter"
renderInput={({ onOptionChange, options, field }) => (
<Typeahead
{...field}
label=""
options={options}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value }) => {
onOptionChange(value, true);
}}
/>
)}
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedCompanies([...selectedCompanies, optionValue]);
@ -227,7 +238,18 @@ export default function QuestionsHomePage() {
<FilterSection
label="Location"
options={locationFilterOptions}
searchPlaceholder="Add location filter"
renderInput={({ onOptionChange, options, field }) => (
<Typeahead
{...field}
label=""
options={options}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onQueryChange={() => {}}
onSelect={({ value }) => {
onOptionChange(value, true);
}}
/>
)}
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedLocations([...selectedLocations, optionValue]);

@ -4,10 +4,12 @@ import type { FilterChoices } from '~/components/questions/filter/FilterSection'
export const COMPANIES: FilterChoices = [
{
id: 'Google',
label: 'Google',
value: 'Google',
},
{
id: 'Meta',
label: 'Meta',
value: 'Meta',
},
@ -16,14 +18,17 @@ export const COMPANIES: FilterChoices = [
// Code, design, behavioral
export const QUESTION_TYPES: FilterChoices<QuestionsQuestionType> = [
{
id: 'CODING',
label: 'Coding',
value: 'CODING',
},
{
id: 'SYSTEM_DESIGN',
label: 'Design',
value: 'SYSTEM_DESIGN',
},
{
id: 'BEHAVIORAL',
label: 'Behavioral',
value: 'BEHAVIORAL',
},
@ -33,18 +38,22 @@ export type QuestionAge = 'all' | 'last-6-months' | 'last-month' | 'last-year';
export const QUESTION_AGES: FilterChoices<QuestionAge> = [
{
id: 'last-month',
label: 'Last month',
value: 'last-month',
},
{
id: 'last-6-months',
label: 'Last 6 months',
value: 'last-6-months',
},
{
id: 'last-year',
label: 'Last year',
value: 'last-year',
},
{
id: 'all',
label: 'All',
value: 'all',
},
@ -52,22 +61,27 @@ export const QUESTION_AGES: FilterChoices<QuestionAge> = [
export const LOCATIONS: FilterChoices = [
{
id: 'Singapore',
label: 'Singapore',
value: 'Singapore',
},
{
id: 'Menlo Park',
label: 'Menlo Park',
value: 'Menlo Park',
},
{
id: 'california',
label: 'California',
value: 'california',
},
{
id: 'california',
label: 'Hong Kong',
value: 'Hong Kong',
},
{
id: 'Taiwan',
label: 'Taiwan',
value: 'Taiwan',
},

Loading…
Cancel
Save