[resumes][feat] Add filter counts on browse page (#446)

pull/448/head
Su Yin 2 years ago committed by GitHub
parent f7df1f7568
commit 45b15ac1b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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">
<CheckboxInput
label={option.label}
label={`${option.label} (${getFilterCount(
filter.label,
option.label,
)})`}
value={userFilters[filter.id].includes(
option.value,
)}

@ -168,6 +168,9 @@ export default function SubmitResumeForm({
onSuccess() {
if (isNewForm) {
trpcContext.invalidateQueries('resumes.resume.findAll');
trpcContext.invalidateQueries(
'resumes.resume.getTotalFilterCounts',
);
router.push('/resumes/browse');
} else {
onClose();

@ -1,6 +1,8 @@
import { z } from 'zod';
import { Vote } from '@prisma/client';
import { EXPERIENCES, LOCATIONS, ROLES } from '~/utils/resumes/resumeFilters';
import { createRouter } from '../context';
import type { Resume } from '~/types/resume';
@ -251,4 +253,72 @@ export const resumesRouter = createRouter()
return topUpvotedCommentCount;
},
})
.query('getTotalFilterCounts', {
async resolve({ ctx }) {
const roleCounts = await ctx.prisma.resumesResume.groupBy({
_count: {
_all: true,
},
by: ['role'],
});
const mappedRoleCounts = Object.fromEntries(
roleCounts.map((rc) => [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,
};
},
});

@ -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<T> = {
export type Filter = {
id: FilterId;
label: string;
label: FilterLabel;
options: Array<FilterOption<FilterValue>>;
};

Loading…
Cancel
Save