From 54f4219262500760d7be0681c802b22d1adf8b27 Mon Sep 17 00:00:00 2001 From: Wu Peirong Date: Thu, 13 Oct 2022 17:20:11 +0800 Subject: [PATCH] [resumes][feat] add sorting of resumes --- .../resumes/browse/ResumeListItem.tsx | 2 +- .../resumes/browse/resumeConstants.ts | 43 +++--- apps/portal/src/pages/resumes/index.tsx | 122 +++++++----------- 3 files changed, 67 insertions(+), 100 deletions(-) diff --git a/apps/portal/src/components/resumes/browse/ResumeListItem.tsx b/apps/portal/src/components/resumes/browse/ResumeListItem.tsx index 53c33e78..c7f7677a 100644 --- a/apps/portal/src/components/resumes/browse/ResumeListItem.tsx +++ b/apps/portal/src/components/resumes/browse/ResumeListItem.tsx @@ -1,4 +1,4 @@ -import { formatDistanceToNow } from 'date-fns'; +import formatDistanceToNow from 'date-fns/formatDistanceToNow'; import Link from 'next/link'; import type { UrlObject } from 'url'; import { ChevronRightIcon } from '@heroicons/react/20/solid'; diff --git a/apps/portal/src/components/resumes/browse/resumeConstants.ts b/apps/portal/src/components/resumes/browse/resumeConstants.ts index b8d85d6e..42d79249 100644 --- a/apps/portal/src/components/resumes/browse/resumeConstants.ts +++ b/apps/portal/src/components/resumes/browse/resumeConstants.ts @@ -4,10 +4,16 @@ export const BROWSE_TABS_VALUES = { STARRED: 'starred', }; -export const SORT_OPTIONS = [ - { current: true, href: '#', name: 'Latest' }, - { current: false, href: '#', name: 'Popular' }, - { current: false, href: '#', name: 'Top Comments' }, +export type SortOrder = 'latest' | 'popular' | 'topComments'; +type SortOption = { + name: string; + value: SortOrder; +}; + +export const SORT_OPTIONS: Array = [ + { name: 'Latest', value: 'latest' }, + { name: 'Popular', value: 'popular' }, + { name: 'Top Comments', value: 'topComments' }, ]; export const TOP_HITS = [ @@ -18,50 +24,45 @@ export const TOP_HITS = [ ]; export type FilterOption = { - checked: boolean; label: string; value: string; }; export const ROLE: Array = [ { - checked: false, label: 'Full-Stack Engineer', value: 'Full-Stack Engineer', }, - { checked: false, label: 'Frontend Engineer', value: 'Frontend Engineer' }, - { checked: false, label: 'Backend Engineer', value: 'Backend Engineer' }, - { checked: false, label: 'DevOps Engineer', value: 'DevOps Engineer' }, - { checked: false, label: 'iOS Engineer', value: 'iOS Engineer' }, - { checked: false, label: 'Android Engineer', value: 'Android Engineer' }, + { label: 'Frontend Engineer', value: 'Frontend Engineer' }, + { label: 'Backend Engineer', value: 'Backend Engineer' }, + { label: 'DevOps Engineer', value: 'DevOps Engineer' }, + { label: 'iOS Engineer', value: 'iOS Engineer' }, + { label: 'Android Engineer', value: 'Android Engineer' }, ]; export const EXPERIENCE: Array = [ - { checked: false, label: 'Freshman', value: 'Freshman' }, - { checked: false, label: 'Sophomore', value: 'Sophomore' }, - { checked: false, label: 'Junior', value: 'Junior' }, - { checked: false, label: 'Senior', value: 'Senior' }, + { label: 'Freshman', value: 'Freshman' }, + { label: 'Sophomore', value: 'Sophomore' }, + { label: 'Junior', value: 'Junior' }, + { label: 'Senior', value: 'Senior' }, { - checked: false, label: 'Fresh Grad (0-1 years)', value: 'Fresh Grad (0-1 years)', }, { - checked: false, label: 'Mid-level (2 - 5 years)', value: 'Mid-level (2 - 5 years)', }, { - checked: false, label: 'Senior (5+ years)', value: 'Senior (5+ years)', }, ]; export const LOCATION: Array = [ - { checked: false, label: 'Singapore', value: 'Singapore' }, - { checked: false, label: 'United States', value: 'United States' }, - { checked: false, label: 'India', value: 'India' }, + { label: 'Singapore', value: 'Singapore' }, + { label: 'United States', value: 'United States' }, + { label: 'India', value: 'India' }, ]; export const TEST_RESUMES = [ diff --git a/apps/portal/src/pages/resumes/index.tsx b/apps/portal/src/pages/resumes/index.tsx index 4dc3fe77..d6631f4d 100644 --- a/apps/portal/src/pages/resumes/index.tsx +++ b/apps/portal/src/pages/resumes/index.tsx @@ -1,18 +1,23 @@ -import clsx from 'clsx'; +import compareAsc from 'date-fns/compareAsc'; import Head from 'next/head'; import { useRouter } from 'next/router'; import { useSession } from 'next-auth/react'; -import { Fragment, useState } from 'react'; -import { Disclosure, Menu, Transition } from '@headlessui/react'; -import { - ChevronDownIcon, - MinusIcon, - PlusIcon, -} from '@heroicons/react/20/solid'; +import { useState } from 'react'; +import { Disclosure } from '@headlessui/react'; +import { MinusIcon, PlusIcon } from '@heroicons/react/20/solid'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; -import { CheckboxInput, CheckboxList, Tabs, TextInput } from '@tih/ui'; +import { + CheckboxInput, + CheckboxList, + DropdownMenu, + Tabs, + TextInput, +} from '@tih/ui'; -import type { FilterOption } from '~/components/resumes/browse/resumeConstants'; +import type { + FilterOption, + SortOrder, +} from '~/components/resumes/browse/resumeConstants'; import { BROWSE_TABS_VALUES, EXPERIENCE, @@ -66,8 +71,8 @@ const filterResumes = ( resumes: Array, searchValue: string, userFilters: FilterState, -) => { - return resumes +) => + resumes .filter((resume) => resume.title.toLowerCase().includes(searchValue.toLocaleLowerCase()), ) @@ -77,12 +82,24 @@ const filterResumes = ( userFilters.experience.includes(experience) && userFilters.location.includes(location), ); + +const sortComparators: Record< + SortOrder, + (resume1: Resume, resume2: Resume) => number +> = { + latest: (resume1, resume2) => + compareAsc(resume2.createdAt, resume1.createdAt), + popular: (resume1, resume2) => resume2.numStars - resume1.numStars, + topComments: (resume1, resume2) => resume2.numComments - resume1.numComments, }; +const sortResumes = (resumes: Array, sortOrder: SortOrder) => + resumes.sort(sortComparators[sortOrder]); export default function ResumeHomePage() { const { data: sessionData } = useSession(); const router = useRouter(); const [tabsValue, setTabsValue] = useState(BROWSE_TABS_VALUES.ALL); + const [sortOrder, setSortOrder] = useState(SORT_OPTIONS[0].value); const [searchValue, setSearchValue] = useState(''); const [userFilters, setUserFilters] = useState(INITIAL_FILTER_STATE); const [resumes, setResumes] = useState>([]); @@ -207,49 +224,17 @@ export default function ResumeHomePage() {
- -
- {/* TODO: Sort logic */} - - Sort - -
- - - -
- {SORT_OPTIONS.map((option) => ( - - {({ active }) => ( - - {option.name} - - )} - - ))} -
-
-
-
+ + {SORT_OPTIONS.map((option) => ( + + setSortOrder(option.value) + }> + ))} +