import Head from 'next/head'; import Router, { useRouter } from 'next/router'; import { useSession } from 'next-auth/react'; import { Fragment, useEffect, useMemo, useState } from 'react'; import { Dialog, Disclosure, Transition } from '@headlessui/react'; import { FunnelIcon, MinusIcon, PlusIcon } from '@heroicons/react/20/solid'; import { MagnifyingGlassIcon, NewspaperIcon, XMarkIcon, } from '@heroicons/react/24/outline'; import type { TypeaheadOption } from '@tih/ui'; import { Button, CheckboxInput, CheckboxList, DropdownMenu, Pagination, Spinner, Tabs, TextInput, } from '@tih/ui'; import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics'; import ResumeFilterPill from '~/components/resumes/browse/ResumeFilterPill'; import ResumeListItems from '~/components/resumes/browse/ResumeListItems'; import ResumeExperienceTypeahead from '~/components/resumes/shared/ResumeExperienceTypeahead'; import ResumeLocationTypeahead from '~/components/resumes/shared/ResumeLocationTypeahead'; import ResumeRoleTypeahead from '~/components/resumes/shared/ResumeRoleTypeahead'; import ResumeSignInButton from '~/components/resumes/shared/ResumeSignInButton'; import loginPageHref from '~/components/shared/loginPageHref'; import type { Filter, FilterId, FilterLabel, Shortcut, } from '~/utils/resumes/resumeFilters'; import type { FilterState, SortOrder } from '~/utils/resumes/resumeFilters'; import { BROWSE_TABS_VALUES, EXPERIENCES, getFilterLabel, INITIAL_FILTER_STATE, isInitialFilterState, LOCATIONS, ROLES, SHORTCUTS, SORT_OPTIONS, } from '~/utils/resumes/resumeFilters'; import useDebounceValue from '~/utils/resumes/useDebounceValue'; import useSearchParams from '~/utils/resumes/useSearchParams'; import { trpc } from '~/utils/trpc'; const STALE_TIME = 5 * 60 * 1000; const DEBOUNCE_DELAY = 800; const PAGE_LIMIT = 10; const filters: Array = [ { id: 'role', label: 'Role', options: ROLES, }, { id: 'experience', label: 'Experience', options: EXPERIENCES, }, { id: 'location', label: 'Location', options: LOCATIONS, }, ]; const getLoggedOutText = (tabsValue: string) => { switch (tabsValue) { case BROWSE_TABS_VALUES.STARRED: return 'to view starred resumes!'; case BROWSE_TABS_VALUES.MY: return 'to view your submitted resumes!'; default: return ''; } }; const getEmptyDataText = ( tabsValue: string, searchValue: string, userFilters: FilterState, ) => { if (searchValue.length > 0) { return 'Try tweaking your search text to see more resumes.'; } if (!isInitialFilterState(userFilters)) { return 'Try tweaking your filters to see more resumes.'; } switch (tabsValue) { case BROWSE_TABS_VALUES.ALL: return "There's nothing to see here..."; case BROWSE_TABS_VALUES.STARRED: return 'You have not starred any resumes. Star one to see it here!'; case BROWSE_TABS_VALUES.MY: return 'Upload a resume to see it here!'; default: return ''; } }; export default function ResumeHomePage() { const { data: sessionData } = useSession(); const router = useRouter(); const [tabsValue, setTabsValue, isTabsValueInit] = useSearchParams( 'tabsValue', BROWSE_TABS_VALUES.ALL, ); const [sortOrder, setSortOrder, isSortOrderInit] = useSearchParams( 'sortOrder', 'latest', ); const [searchValue, setSearchValue, isSearchValueInit] = useSearchParams( 'searchValue', '', ); const [shortcutSelected, setShortcutSelected, isShortcutInit] = useSearchParams('shortcutSelected', 'Unreviewed'); const [currentPage, setCurrentPage, isCurrentPageInit] = useSearchParams( 'currentPage', 1, ); const [userFilters, setUserFilters, isUserFiltersInit] = useSearchParams( 'userFilters', INITIAL_FILTER_STATE, ); const [isFiltersOpen, setIsFiltersOpen, isFiltersOpenInit] = useSearchParams< Record >('isFiltersOpen', { experience: false, location: false, role: false, }); const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false); const { event: gaEvent } = useGoogleAnalytics(); const skip = (currentPage - 1) * PAGE_LIMIT; const isSearchOptionsInit = useMemo(() => { return ( isTabsValueInit && isSortOrderInit && isSearchValueInit && isShortcutInit && isCurrentPageInit && isUserFiltersInit && isFiltersOpenInit ); }, [ isTabsValueInit, isSortOrderInit, isSearchValueInit, isShortcutInit, isCurrentPageInit, isUserFiltersInit, isFiltersOpenInit, ]); useEffect(() => { setCurrentPage(1); }, [userFilters, sortOrder, setCurrentPage, searchValue]); useEffect(() => { // Router.replace used instead of router.replace to avoid // the page reloading itself since the router.replace // callback changes on every page load if (!isSearchOptionsInit) { return; } Router.replace({ pathname: router.pathname, query: { currentPage: JSON.stringify(currentPage), isFiltersOpen: JSON.stringify(isFiltersOpen), searchValue: JSON.stringify(searchValue), shortcutSelected: JSON.stringify(shortcutSelected), sortOrder: JSON.stringify(sortOrder), tabsValue: JSON.stringify(tabsValue), userFilters: JSON.stringify(userFilters), }, }); }, [ tabsValue, sortOrder, searchValue, userFilters, shortcutSelected, currentPage, router.pathname, isSearchOptionsInit, isFiltersOpen, ]); const allResumesQuery = trpc.useQuery( [ 'resumes.resume.findAll', { experienceFilters: userFilters.experience.map(({ value }) => value), isUnreviewed: userFilters.isUnreviewed, locationFilters: userFilters.location.map(({ value }) => value), roleFilters: userFilters.role.map(({ value }) => value), searchValue: useDebounceValue(searchValue, DEBOUNCE_DELAY), skip, sortOrder, take: PAGE_LIMIT, }, ], { enabled: tabsValue === BROWSE_TABS_VALUES.ALL, staleTime: STALE_TIME, }, ); const starredResumesQuery = trpc.useQuery( [ 'resumes.resume.user.findUserStarred', { experienceFilters: userFilters.experience.map(({ value }) => value), isUnreviewed: userFilters.isUnreviewed, locationFilters: userFilters.location.map(({ value }) => value), roleFilters: userFilters.role.map(({ value }) => value), searchValue: useDebounceValue(searchValue, DEBOUNCE_DELAY), skip, sortOrder, take: PAGE_LIMIT, }, ], { enabled: tabsValue === BROWSE_TABS_VALUES.STARRED, retry: false, staleTime: STALE_TIME, }, ); const myResumesQuery = trpc.useQuery( [ 'resumes.resume.user.findUserCreated', { experienceFilters: userFilters.experience.map(({ value }) => value), isUnreviewed: userFilters.isUnreviewed, locationFilters: userFilters.location.map(({ value }) => value), roleFilters: userFilters.role.map(({ value }) => value), searchValue: useDebounceValue(searchValue, DEBOUNCE_DELAY), skip, sortOrder, take: PAGE_LIMIT, }, ], { enabled: tabsValue === BROWSE_TABS_VALUES.MY, retry: false, staleTime: STALE_TIME, }, ); const onSubmitResume = () => { if (sessionData === null) { router.push(loginPageHref()); } else { router.push('/resumes/submit'); } }; const onClearFilterClick = (filterSection: FilterId) => { setUserFilters({ ...userFilters, [filterSection]: [], }); }; const onShortcutChange = ({ sortOrder: shortcutSortOrder, filters: shortcutFilters, name: shortcutName, }: Shortcut) => { setShortcutSelected(shortcutName); setSortOrder(shortcutSortOrder); setUserFilters(shortcutFilters); gaEvent({ action: 'resumes.shortcut_button_click', category: 'engagement', label: `Select Shortcut: ${shortcutName}`, }); }; const onTabChange = (tab: string) => { setTabsValue(tab); setCurrentPage(1); gaEvent({ action: 'resumes.tab_click', category: 'engagement', label: `Select Tab: ${tab}`, }); }; const getTabQueryData = () => { switch (tabsValue) { case BROWSE_TABS_VALUES.ALL: return allResumesQuery.data; case BROWSE_TABS_VALUES.STARRED: return starredResumesQuery.data; case BROWSE_TABS_VALUES.MY: return myResumesQuery.data; default: return null; } }; const getTabResumes = () => { return getTabQueryData()?.mappedResumeData ?? []; }; const getTabTotalPages = () => { const numRecords = getTabQueryData()?.totalRecords ?? 0; return numRecords % PAGE_LIMIT === 0 ? numRecords / PAGE_LIMIT : Math.floor(numRecords / PAGE_LIMIT) + 1; }; const isFetchingResumes = allResumesQuery.isFetching || starredResumesQuery.isFetching || myResumesQuery.isFetching; const getTabFilterCounts = () => { return getTabQueryData()?.filterCounts; }; const getFilterTypeahead = (filterId: FilterId) => { const onSelect = (option: TypeaheadOption | null) => { if (option === null) { return; } setUserFilters({ ...userFilters, [filterId]: [...userFilters[filterId], option], }); gaEvent({ action: 'resumes.filter_typeahead_click', category: 'engagement', label: 'Select Filter', }); }; switch (filterId) { case 'experience': return ( value)) } onSelect={onSelect} /> ); case 'location': return ( value)) } onSelect={onSelect} /> ); case 'role': return ( value)) } onSelect={onSelect} /> ); default: return null; } }; const getFilterCount = (filter: FilterLabel, value: string) => { const filterCountsData = getTabFilterCounts(); if (!filterCountsData) { return 0; } return filterCountsData[filter][value]; }; return ( <> Resume Review Portal {/* Mobile Filters */}

Quick access

    {SHORTCUTS.map((shortcut) => (
  • onShortcutChange(shortcut)} />
  • ))}
{filters.map((filter) => ( {({ open }) => ( <>

setIsFiltersOpen({ ...isFiltersOpen, [filter.id]: !isFiltersOpen[filter.id], }) }> {filter.label} {open ? (

{getFilterTypeahead(filter.id)} {userFilters[filter.id].map((option) => (
setUserFilters({ ...userFilters, [filter.id]: userFilters[ filter.id ].filter( ({ value }) => value !== option.value, ), }) } /> ( {getFilterCount( filter.label, option.label, )} )
))}

onClearFilterClick(filter.id)}> Clear

)}
))}
{/* Quick Access Section */}

Quick access

    {SHORTCUTS.map((shortcut) => (
  • onShortcutChange(shortcut)} />
  • ))}
{/* Filter Section */}

Explore these filters

{isFiltersOpenInit && filters.map((filter) => ( {({ open }) => ( <>

setIsFiltersOpen({ ...isFiltersOpen, [filter.id]: !isFiltersOpen[filter.id], }) }> {filter.label} {open ? (

{getFilterTypeahead(filter.id)} {userFilters[filter.id].map((option) => (
setUserFilters({ ...userFilters, [filter.id]: userFilters[ filter.id ].filter( ({ value }) => value !== option.value, ), }) } /> ( {getFilterCount(filter.label, option.label)} )
))}

onClearFilterClick(filter.id)}> Clear

)}
))}
gaEvent({ action: 'resumes.search_input_focus', category: 'engagement', label: 'Click Search', }) } />
{SORT_OPTIONS.map(({ label, value }) => ( setSortOrder(value)}> ))}
{isFetchingResumes ? (
{' '} {' '}
) : sessionData === null && tabsValue !== BROWSE_TABS_VALUES.ALL ? ( ) : getTabResumes().length === 0 ? (
{getEmptyDataText(tabsValue, searchValue, userFilters)}
) : (
{getTabTotalPages() > 1 && (
setCurrentPage(page)} />
)}
)}
); }