[questions][ui] improve search filter robustness

pull/411/head
Jeff Sieu 3 years ago
parent 9c1e179347
commit 8032f77a70

@ -1,7 +1,6 @@
import { startOfMonth } from 'date-fns'; import { startOfMonth } from 'date-fns';
import { useState } from 'react'; import { useState } from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { CalendarDaysIcon, UserIcon } from '@heroicons/react/24/outline';
import type { QuestionsQuestionType } from '@prisma/client'; import type { QuestionsQuestionType } from '@prisma/client';
import { import {
Button, Button,
@ -9,10 +8,10 @@ import {
HorizontalDivider, HorizontalDivider,
Select, Select,
TextArea, TextArea,
TextInput, Typeahead,
} from '@tih/ui'; } from '@tih/ui';
import { QUESTION_TYPES } from '~/utils/questions/constants'; import { LOCATIONS, QUESTION_TYPES, ROLES } from '~/utils/questions/constants';
import { import {
useFormRegister, useFormRegister,
useSelectRegister, useSelectRegister,
@ -83,12 +82,25 @@ export default function ContributeQuestionForm({
</h2> </h2>
<div className="flex flex-col flex-wrap items-stretch gap-2 sm:flex-row sm:items-end"> <div className="flex flex-col flex-wrap items-stretch gap-2 sm:flex-row sm:items-end">
<div className="flex-1 sm:min-w-[150px] sm:max-w-[300px]"> <div className="flex-1 sm:min-w-[150px] sm:max-w-[300px]">
<TextInput <Controller
control={control}
name="location"
render={({ field }) => (
<Typeahead
label="Location" label="Location"
options={LOCATIONS}
required={true} required={true}
startAddOn={CalendarDaysIcon} // eslint-disable-next-line @typescript-eslint/no-empty-function
startAddOnType="icon" onQueryChange={() => {}}
{...register('location')} onSelect={(option) => {
field.onChange(option.value);
}}
{...field}
value={LOCATIONS.find(
(location) => location.value === field.value,
)}
/>
)}
/> />
</div> </div>
<div className="flex-1 sm:min-w-[150px] sm:max-w-[300px]"> <div className="flex-1 sm:min-w-[150px] sm:max-w-[300px]">
@ -97,10 +109,12 @@ export default function ContributeQuestionForm({
name="date" name="date"
render={({ field }) => ( render={({ field }) => (
<MonthYearPicker <MonthYearPicker
monthRequired={true}
value={{ value={{
month: ((field.value.getMonth() as number) + 1) as Month, month: ((field.value.getMonth() as number) + 1) as Month,
year: field.value.getFullYear(), year: field.value.getFullYear(),
}} }}
yearRequired={true}
onChange={({ month, year }) => onChange={({ month, year }) =>
field.onChange(startOfMonth(new Date(year, month - 1))) field.onChange(startOfMonth(new Date(year, month - 1)))
} }
@ -124,12 +138,23 @@ export default function ContributeQuestionForm({
/> />
</div> </div>
<div className="flex-1 sm:min-w-[150px] sm:max-w-[200px]"> <div className="flex-1 sm:min-w-[150px] sm:max-w-[200px]">
<TextInput <Controller
control={control}
name="role"
render={({ field }) => (
<Typeahead
label="Role" label="Role"
options={ROLES}
required={true} required={true}
startAddOn={UserIcon} // eslint-disable-next-line @typescript-eslint/no-empty-function
startAddOnType="icon" onQueryChange={() => {}}
{...register('role')} onSelect={(option) => {
field.onChange(option.value);
}}
{...field}
value={ROLES.find((role) => role.value === field.value)}
/>
)}
/> />
</div> </div>
</div> </div>

@ -38,7 +38,12 @@ export default function QuestionsHomePage() {
areQuestionTypesInitialized, areQuestionTypesInitialized,
] = useSearchFilter<QuestionsQuestionType>('questionTypes', { ] = useSearchFilter<QuestionsQuestionType>('questionTypes', {
queryParamToValue: (param) => { queryParamToValue: (param) => {
return param.toUpperCase() as QuestionsQuestionType; const uppercaseParam = param.toUpperCase();
return (
QUESTION_TYPES.find(
(questionType) => questionType.value.toUpperCase() === uppercaseParam,
)?.value ?? null
);
}, },
}); });
const [ const [
@ -47,6 +52,14 @@ export default function QuestionsHomePage() {
isQuestionAgeInitialized, isQuestionAgeInitialized,
] = useSearchFilterSingle<QuestionAge>('questionAge', { ] = useSearchFilterSingle<QuestionAge>('questionAge', {
defaultValue: 'all', defaultValue: 'all',
queryParamToValue: (param) => {
const uppercaseParam = param.toUpperCase();
return (
QUESTION_AGES.find(
(questionAge) => questionAge.value.toUpperCase() === uppercaseParam,
)?.value ?? null
);
},
}); });
const [selectedRoles, setSelectedRoles, areRolesInitialized] = const [selectedRoles, setSelectedRoles, areRolesInitialized] =

@ -80,6 +80,8 @@ export const questionsQuestionRouter = createProtectedRouter()
}, },
}, },
}); });
console.log(input);
return questionsData.map((data) => { return questionsData.map((data) => {
const votes: number = data.votes.reduce( const votes: number = data.votes.reduce(
(previousValue: number, currentValue) => { (previousValue: number, currentValue) => {

@ -76,7 +76,7 @@ export const LOCATIONS: FilterChoices = [
value: 'california', value: 'california',
}, },
{ {
id: 'california', id: 'Hong Kong',
label: 'Hong Kong', label: 'Hong Kong',
value: 'Hong Kong', value: 'Hong Kong',
}, },

@ -5,7 +5,7 @@ export const useSearchFilter = <Value extends string = string>(
name: string, name: string,
opts: { opts: {
defaultValues?: Array<Value>; defaultValues?: Array<Value>;
queryParamToValue?: (param: string) => Value; queryParamToValue?: (param: string) => Value | null;
} = {}, } = {},
) => { ) => {
const { defaultValues, queryParamToValue = (param) => param } = opts; const { defaultValues, queryParamToValue = (param) => param } = opts;
@ -20,7 +20,11 @@ export const useSearchFilter = <Value extends string = string>(
const query = router.query[name]; const query = router.query[name];
if (query) { if (query) {
const queryValues = Array.isArray(query) ? query : [query]; const queryValues = Array.isArray(query) ? query : [query];
setFilters(queryValues.map(queryParamToValue) as Array<Value>); setFilters(
queryValues
.map(queryParamToValue)
.filter((value) => value !== null) as Array<Value>,
);
} else { } else {
// Try to load from local storage // Try to load from local storage
const localStorageValue = localStorage.getItem(name); const localStorageValue = localStorage.getItem(name);
@ -48,7 +52,7 @@ export const useSearchFilterSingle = <Value extends string = string>(
name: string, name: string,
opts: { opts: {
defaultValue?: Value; defaultValue?: Value;
queryParamToValue?: (param: string) => Value; queryParamToValue?: (param: string) => Value | null;
} = {}, } = {},
) => { ) => {
const { defaultValue, queryParamToValue } = opts; const { defaultValue, queryParamToValue } = opts;

Loading…
Cancel
Save