From 45b15ac1b3a09377d749991b172e35bba6af9ac4 Mon Sep 17 00:00:00 2001 From: Su Yin <53945359+tnsyn@users.noreply.github.com> Date: Thu, 27 Oct 2022 21:30:37 +0800 Subject: [PATCH] [resumes][feat] Add filter counts on browse page (#446) --- apps/portal/src/pages/resumes/browse.tsx | 27 ++++++- apps/portal/src/pages/resumes/submit.tsx | 3 + .../router/resumes/resumes-resume-router.ts | 70 +++++++++++++++++++ .../portal/src/utils/resumes/resumeFilters.ts | 3 +- 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/apps/portal/src/pages/resumes/browse.tsx b/apps/portal/src/pages/resumes/browse.tsx index f8a07b54..a5a44c35 100644 --- a/apps/portal/src/pages/resumes/browse.tsx +++ b/apps/portal/src/pages/resumes/browse.tsx @@ -24,7 +24,12 @@ import ResumeFilterPill from '~/components/resumes/browse/ResumeFilterPill'; import ResumeListItems from '~/components/resumes/browse/ResumeListItems'; import ResumeSignInButton from '~/components/resumes/shared/ResumeSignInButton'; -import type { Filter, FilterId, Shortcut } from '~/utils/resumes/resumeFilters'; +import type { + Filter, + FilterId, + FilterLabel, + Shortcut, +} from '~/utils/resumes/resumeFilters'; import { BROWSE_TABS_VALUES, EXPERIENCES, @@ -177,6 +182,13 @@ export default function ResumeHomePage() { isSearchOptionsInit, ]); + const filterCountsQuery = trpc.useQuery( + ['resumes.resume.getTotalFilterCounts'], + { + staleTime: STALE_TIME, + }, + ); + const allResumesQuery = trpc.useQuery( [ 'resumes.resume.findAll', @@ -237,6 +249,14 @@ export default function ResumeHomePage() { }, ); + const getFilterCount = (filter: FilterLabel, value: string) => { + if (filterCountsQuery.isLoading) { + return 0; + } + const filterCountsData = filterCountsQuery.data!; + return filterCountsData[filter][value]; + }; + const onSubmitResume = () => { if (sessionData === null) { router.push('/api/auth/signin'); @@ -495,7 +515,10 @@ export default function ResumeHomePage() { key={option.value} className="[&>div>div:nth-child(1)>input]:text-primary-600 [&>div>div:nth-child(1)>input]:ring-primary-500 px-1 [&>div>div:nth-child(2)>label]:font-normal"> [rc.role, rc._count._all]), + ); + const zeroRoleCounts = Object.fromEntries( + ROLES.filter((r) => !(r.value in mappedRoleCounts)).map((r) => [ + r.value, + 0, + ]), + ); + const processedRoleCounts = { + ...mappedRoleCounts, + ...zeroRoleCounts, + }; + + const experienceCounts = await ctx.prisma.resumesResume.groupBy({ + _count: { + _all: true, + }, + by: ['experience'], + }); + const mappedExperienceCounts = Object.fromEntries( + experienceCounts.map((ec) => [ec.experience, ec._count._all]), + ); + const zeroExperienceCounts = Object.fromEntries( + EXPERIENCES.filter((e) => !(e.value in mappedExperienceCounts)).map( + (e) => [e.value, 0], + ), + ); + const processedExperienceCounts = { + ...mappedExperienceCounts, + ...zeroExperienceCounts, + }; + + const locationCounts = await ctx.prisma.resumesResume.groupBy({ + _count: { + _all: true, + }, + by: ['location'], + }); + const mappedLocationCounts = Object.fromEntries( + locationCounts.map((lc) => [lc.location, lc._count._all]), + ); + const zeroLocationCounts = Object.fromEntries( + LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [ + l.value, + 0, + ]), + ); + const processedLocationCounts = { + ...mappedLocationCounts, + ...zeroLocationCounts, + }; + + return { + Experience: processedExperienceCounts, + Location: processedLocationCounts, + Role: processedRoleCounts, + }; + }, }); diff --git a/apps/portal/src/utils/resumes/resumeFilters.ts b/apps/portal/src/utils/resumes/resumeFilters.ts index 31ab5a3f..cf030d4e 100644 --- a/apps/portal/src/utils/resumes/resumeFilters.ts +++ b/apps/portal/src/utils/resumes/resumeFilters.ts @@ -1,4 +1,5 @@ export type FilterId = 'experience' | 'location' | 'role'; +export type FilterLabel = 'Experience' | 'Location' | 'Role'; export type CustomFilter = { numComments: number; @@ -29,7 +30,7 @@ export type FilterOption = { export type Filter = { id: FilterId; - label: string; + label: FilterLabel; options: Array>; };