[resumes][feat] add filtering for resumes

pull/374/head
Wu Peirong 3 years ago
parent 6413bb755e
commit 58cc7604af

@ -17,7 +17,13 @@ export const TOP_HITS = [
{ href: '#', name: 'US Only' }, { href: '#', name: 'US Only' },
]; ];
export const ROLES = [ export type FilterOption = {
checked: boolean;
label: string;
value: string;
};
export const ROLE: Array<FilterOption> = [
{ {
checked: false, checked: false,
label: 'Full-Stack Engineer', label: 'Full-Stack Engineer',
@ -30,7 +36,7 @@ export const ROLES = [
{ checked: false, label: 'Android Engineer', value: 'Android Engineer' }, { checked: false, label: 'Android Engineer', value: 'Android Engineer' },
]; ];
export const EXPERIENCE = [ export const EXPERIENCE: Array<FilterOption> = [
{ checked: false, label: 'Freshman', value: 'Freshman' }, { checked: false, label: 'Freshman', value: 'Freshman' },
{ checked: false, label: 'Sophomore', value: 'Sophomore' }, { checked: false, label: 'Sophomore', value: 'Sophomore' },
{ checked: false, label: 'Junior', value: 'Junior' }, { checked: false, label: 'Junior', value: 'Junior' },
@ -52,7 +58,7 @@ export const EXPERIENCE = [
}, },
]; ];
export const LOCATION = [ export const LOCATION: Array<FilterOption> = [
{ checked: false, label: 'Singapore', value: 'Singapore' }, { checked: false, label: 'Singapore', value: 'Singapore' },
{ checked: false, label: 'United States', value: 'United States' }, { checked: false, label: 'United States', value: 'United States' },
{ checked: false, label: 'India', value: 'India' }, { checked: false, label: 'India', value: 'India' },

@ -10,13 +10,14 @@ import {
PlusIcon, PlusIcon,
} from '@heroicons/react/20/solid'; } from '@heroicons/react/20/solid';
import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline';
import { Tabs, TextInput } from '@tih/ui'; import { CheckboxInput, CheckboxList, Tabs, TextInput } from '@tih/ui';
import type { FilterOption } from '~/components/resumes/browse/resumeConstants';
import { import {
BROWSE_TABS_VALUES, BROWSE_TABS_VALUES,
EXPERIENCE, EXPERIENCE,
LOCATION, LOCATION,
ROLES, ROLE,
SORT_OPTIONS, SORT_OPTIONS,
TOP_HITS, TOP_HITS,
} from '~/components/resumes/browse/resumeConstants'; } from '~/components/resumes/browse/resumeConstants';
@ -29,11 +30,19 @@ import { trpc } from '~/utils/trpc';
import type { Resume } from '~/types/resume'; import type { Resume } from '~/types/resume';
const filters = [ type FilterId = 'experience' | 'location' | 'role';
type Filter = {
id: FilterId;
name: string;
options: Array<FilterOption>;
};
type FilterState = Record<FilterId, Array<string>>;
const filters: Array<Filter> = [
{ {
id: 'roles', id: 'role',
name: 'Roles', name: 'Role',
options: ROLES, options: ROLE,
}, },
{ {
id: 'experience', id: 'experience',
@ -47,11 +56,35 @@ const filters = [
}, },
]; ];
const INITIAL_FILTER_STATE: FilterState = {
experience: Object.values(EXPERIENCE).map(({ value }) => value),
location: Object.values(LOCATION).map(({ value }) => value),
role: Object.values(ROLE).map(({ value }) => value),
};
const filterResumes = (
resumes: Array<Resume>,
searchValue: string,
userFilters: FilterState,
) => {
return resumes
.filter((resume) =>
resume.title.toLowerCase().includes(searchValue.toLocaleLowerCase()),
)
.filter(
({ experience, location, role }) =>
userFilters.role.includes(role) &&
userFilters.experience.includes(experience) &&
userFilters.location.includes(location),
);
};
export default function ResumeHomePage() { export default function ResumeHomePage() {
const { data: sessionData } = useSession(); const { data: sessionData } = useSession();
const router = useRouter(); const router = useRouter();
const [tabsValue, setTabsValue] = useState(BROWSE_TABS_VALUES.ALL); const [tabsValue, setTabsValue] = useState(BROWSE_TABS_VALUES.ALL);
const [searchValue, setSearchValue] = useState(''); const [searchValue, setSearchValue] = useState('');
const [userFilters, setUserFilters] = useState(INITIAL_FILTER_STATE);
const [resumes, setResumes] = useState<Array<Resume>>([]); const [resumes, setResumes] = useState<Array<Resume>>([]);
const [renderSignInButton, setRenderSignInButton] = useState(false); const [renderSignInButton, setRenderSignInButton] = useState(false);
const [signInButtonText, setSignInButtonText] = useState(''); const [signInButtonText, setSignInButtonText] = useState('');
@ -102,6 +135,26 @@ export default function ResumeHomePage() {
} }
}; };
const onFilterCheckboxChange = (
isChecked: boolean,
filterSection: FilterId,
filterValue: string,
) => {
if (isChecked) {
setUserFilters({
...userFilters,
[filterSection]: [...userFilters[filterSection], filterValue],
});
} else {
setUserFilters({
...userFilters,
[filterSection]: userFilters[filterSection].filter(
(value) => value !== filterValue,
),
});
}
};
return ( return (
<> <>
<Head> <Head>
@ -256,8 +309,8 @@ export default function ResumeHomePage() {
</span> </span>
</Disclosure.Button> </Disclosure.Button>
</h3> </h3>
<Disclosure.Panel className="pt-6"> <Disclosure.Panel className="pt-4">
<div className="space-y-4"> {/* <div className="space-y-4">
{section.options.map((option, optionIdx) => ( {section.options.map((option, optionIdx) => (
<div <div
key={option.value} key={option.value}
@ -269,6 +322,7 @@ export default function ResumeHomePage() {
id={`filter-${section.id}-${optionIdx}`} id={`filter-${section.id}-${optionIdx}`}
name={`${section.id}[]`} name={`${section.id}[]`}
type="checkbox" type="checkbox"
onChange={(value) => console.log(value)}
/> />
<label <label
className="ml-3 text-sm text-gray-600" className="ml-3 text-sm text-gray-600"
@ -277,7 +331,32 @@ export default function ResumeHomePage() {
</label> </label>
</div> </div>
))} ))}
</div> </div> */}
<CheckboxList
description=""
isLabelHidden={true}
label=""
orientation="vertical">
{section.options.map((option) => (
<div
key={option.value}
className="[&>div>div:nth-child(2)>label]:font-normal [&>div>div:nth-child(1)>input]:text-indigo-600 [&>div>div:nth-child(1)>input]:ring-indigo-500">
<CheckboxInput
label={option.label}
value={userFilters[section.id].includes(
option.value,
)}
onChange={(isChecked) =>
onFilterCheckboxChange(
isChecked,
section.id,
option.value,
)
}
/>
</div>
))}
</CheckboxList>
</Disclosure.Panel> </Disclosure.Panel>
</> </>
)} )}
@ -296,7 +375,7 @@ export default function ResumeHomePage() {
starredResumesQuery.isFetching || starredResumesQuery.isFetching ||
myResumesQuery.isFetching myResumesQuery.isFetching
} }
resumes={resumes} resumes={filterResumes(resumes, searchValue, userFilters)}
/> />
</div> </div>
</div> </div>

@ -11,7 +11,7 @@ import { Button, CheckboxInput, Select, TextArea, TextInput } from '@tih/ui';
import { import {
EXPERIENCE, EXPERIENCE,
LOCATION, LOCATION,
ROLES, ROLE,
} from '~/components/resumes/browse/resumeConstants'; } from '~/components/resumes/browse/resumeConstants';
import { RESUME_STORAGE_KEY } from '~/constants/file-storage-keys'; import { RESUME_STORAGE_KEY } from '~/constants/file-storage-keys';
@ -152,7 +152,7 @@ export default function SubmitResumeForm() {
{...register('role', { required: true })} {...register('role', { required: true })}
disabled={isLoading} disabled={isLoading}
label="Role" label="Role"
options={ROLES} options={ROLE}
required={true} required={true}
onChange={(val) => setValue('role', val)} onChange={(val) => setValue('role', val)}
/> />

Loading…
Cancel
Save