[questions][feat] add filter section

pull/312/head
Jeff Sieu 3 years ago
parent 3301f7de2f
commit 5a09053c73

@ -57,7 +57,7 @@ export default function ContributeQuestionCard({
{...register('questionContent')}
/>
<div className="flex items-end justify-center gap-x-2">
<div className="flex-1">
<div className="min-w-[150px] flex-1">
<FormTextInput
label="Company"
startAddOn={BuildingOffice2Icon}
@ -65,7 +65,7 @@ export default function ContributeQuestionCard({
{...register('company')}
/>
</div>
<div className="flex-1">
<div className="min-w-[150px] flex-1">
<FormTextInput
label="Question type"
startAddOn={QuestionMarkCircleIcon}
@ -73,7 +73,7 @@ export default function ContributeQuestionCard({
{...register('questionType')}
/>
</div>
<div className="flex-1">
<div className="min-w-[150px] flex-1">
<FormTextInput
label="Date"
startAddOn={CalendarDaysIcon}

@ -0,0 +1,62 @@
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { Collapsible, TextInput } from '@tih/ui';
import Checkbox from '../ui-patch/Checkbox';
export type FilterOptions = {
checked: boolean;
label: string;
value: string;
};
export type FilterSectionProps = {
label: string;
onOptionChange: (optionValue: string, checked: boolean) => void;
options: Array<FilterOptions>;
} & (
| {
searchPlaceholder: string;
showAll?: never;
}
| {
searchPlaceholder?: never;
showAll: true;
}
);
export default function FilterSection({
label,
options,
searchPlaceholder,
showAll,
onOptionChange,
}: FilterSectionProps) {
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="mx-1">
{options.map((option) => (
<Checkbox
key={option.value}
{...option}
onChange={(checked) => {
onOptionChange(option.value, checked);
}}
/>
))}
</div>
</div>
</Collapsible>
</div>
);
}

@ -0,0 +1,25 @@
import { useId } from 'react';
export type CheckboxProps = {
checked: boolean;
label: string;
onChange: (checked: boolean) => void;
};
export default function Checkbox({ label, checked, onChange }: CheckboxProps) {
const id = useId();
return (
<div className="flex items-center">
<input
checked={checked}
className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-gray-300"
id={id}
type="checkbox"
onChange={(event) => onChange(event.target.checked)}
/>
<label className="ml-3 min-w-0 flex-1 text-gray-700" htmlFor={id}>
{label}
</label>
</div>
);
}

@ -1,15 +1,168 @@
import { useMemo, useState } from 'react';
import ContributeQuestionCard from '~/components/questions/ContributeQuestionCard';
import type { FilterOptions } from '~/components/questions/filter/FilterSection';
import FilterSection from '~/components/questions/filter/FilterSection';
import NavBar from '~/components/questions/NavBar';
import QuestionOverviewCard from '~/components/questions/QuestionOverviewCard';
import QuestionSearchBar from '~/components/questions/QuestionSearchBar';
type FilterChoices = Array<Omit<FilterOptions, 'checked'>>;
const companies: FilterChoices = [
{
label: 'Google',
value: 'Google',
},
{
label: 'Meta',
value: 'meta',
},
];
// Code, design, behavioral
const questionTypes: FilterChoices = [
{
label: 'Code',
value: 'code',
},
{
label: 'Design',
value: 'design',
},
{
label: 'Behavioral',
value: 'behavioral',
},
];
const questionAges: FilterChoices = [
{
label: 'Last month',
value: 'last-month',
},
{
label: 'Last 6 months',
value: 'last-6-months',
},
{
label: 'Last year',
value: 'last-year',
},
];
const locations: FilterChoices = [
{
label: 'Singapore',
value: 'singapore',
},
];
export default function QuestionsHomePage() {
const [selectedCompanies, setSelectedCompanies] = useState<Array<string>>([]);
const [selectedQuestionTypes, setSelectedQuestionTypes] = useState<
Array<string>
>([]);
const [selectedQuestionAges, setSelectedQuestionAges] = useState<
Array<string>
>([]);
const [selectedLocations, setSelectedLocations] = useState<Array<string>>([]);
const companyFilterOptions = useMemo(() => {
return companies.map((company) => ({
...company,
checked: selectedCompanies.includes(company.value),
}));
}, [selectedCompanies]);
const questionTypeFilterOptions = useMemo(() => {
return questionTypes.map((questionType) => ({
...questionType,
checked: selectedQuestionTypes.includes(questionType.value),
}));
}, [selectedQuestionTypes]);
const questionAgeFilterOptions = useMemo(() => {
return questionAges.map((questionAge) => ({
...questionAge,
checked: selectedQuestionAges.includes(questionAge.value),
}));
}, [selectedQuestionAges]);
const locationFilterOptions = useMemo(() => {
return locations.map((location) => ({
...location,
checked: selectedLocations.includes(location.value),
}));
}, [selectedLocations]);
return (
<main className="flex flex-1 flex-col items-center justify-center overflow-y-auto">
<main className="flex flex-1 flex-col justify-center items-center overflow-y-auto p-4">
<div className="w-full pb-4">
<NavBar></NavBar>
</div>
<div className="flex max-w-4xl flex-1 gap-x-4">
<div className="flex max-w-6xl flex-1 gap-x-4">
<section className=" w-[300px] border-r px-4">
<h2 className="text-xl font-semibold">Filter by</h2>
<div className="divide-y divide-slate-200">
<FilterSection
label="Company"
options={companyFilterOptions}
searchPlaceholder="Add company filter"
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedCompanies((prev) => [...prev, optionValue]);
} else {
setSelectedCompanies((prev) =>
prev.filter((company) => company !== optionValue),
);
}
}}
/>
<FilterSection
label="Question types"
options={questionTypeFilterOptions}
showAll={true}
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedQuestionTypes((prev) => [...prev, optionValue]);
} else {
setSelectedQuestionTypes((prev) =>
prev.filter((questionType) => questionType !== optionValue),
);
}
}}
/>
<FilterSection
label="Question age"
options={questionAgeFilterOptions}
showAll={true}
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedQuestionAges((prev) => [...prev, optionValue]);
} else {
setSelectedQuestionAges((prev) =>
prev.filter((questionAge) => questionAge !== optionValue),
);
}
}}
/>
<FilterSection
label="Location"
options={locationFilterOptions}
searchPlaceholder="Add location filter"
onOptionChange={(optionValue, checked) => {
if (checked) {
setSelectedLocations((prev) => [...prev, optionValue]);
} else {
setSelectedLocations((prev) =>
prev.filter((location) => location !== optionValue),
);
}
}}
/>
</div>
</section>
<div className="flex flex-1 flex-col items-stretch justify-start gap-4">
<ContributeQuestionCard
onSubmit={(data) => {
@ -40,9 +193,6 @@ export default function QuestionsHomePage() {
upvoteCount={0}
/>
</div>
<div className="flex flex-col items-center justify-center">
<h1>To do: Filter column</h1>
</div>
</div>
</main>
);

@ -23,7 +23,7 @@ export default function Collapsible({ children, defaultOpen, label }: Props) {
/>
<span className="flex-1">{label}</span>
</Disclosure.Button>
<Disclosure.Panel className="pt-1 pb-2 text-sm text-gray-500">
<Disclosure.Panel className="w-full pt-1 pb-2 text-sm text-gray-500">
{children}
</Disclosure.Panel>
</>

Loading…
Cancel
Save