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

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 ResumeListItems from '~/components/resumes/browse/ResumeListItems';
import ResumeSignInButton from '~/components/resumes/shared/ResumeSignInButton'; 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 { import {
BROWSE_TABS_VALUES, BROWSE_TABS_VALUES,
EXPERIENCES, EXPERIENCES,
@ -177,6 +182,13 @@ export default function ResumeHomePage() {
isSearchOptionsInit, isSearchOptionsInit,
]); ]);
const filterCountsQuery = trpc.useQuery(
['resumes.resume.getTotalFilterCounts'],
{
staleTime: STALE_TIME,
},
);
const allResumesQuery = trpc.useQuery( const allResumesQuery = trpc.useQuery(
[ [
'resumes.resume.findAll', '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 = () => { const onSubmitResume = () => {
if (sessionData === null) { if (sessionData === null) {
router.push('/api/auth/signin'); router.push('/api/auth/signin');
@ -495,7 +515,10 @@ export default function ResumeHomePage() {
key={option.value} 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"> 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 <CheckboxInput
label={option.label} label={`${option.label} (${getFilterCount(
filter.label,
option.label,
)})`}
value={userFilters[filter.id].includes( value={userFilters[filter.id].includes(
option.value, option.value,
)} )}

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

@ -1,6 +1,8 @@
import { z } from 'zod'; import { z } from 'zod';
import { Vote } from '@prisma/client'; import { Vote } from '@prisma/client';
import { EXPERIENCES, LOCATIONS, ROLES } from '~/utils/resumes/resumeFilters';
import { createRouter } from '../context'; import { createRouter } from '../context';
import type { Resume } from '~/types/resume'; import type { Resume } from '~/types/resume';
@ -251,4 +253,72 @@ export const resumesRouter = createRouter()
return topUpvotedCommentCount; 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 FilterId = 'experience' | 'location' | 'role';
export type FilterLabel = 'Experience' | 'Location' | 'Role';
export type CustomFilter = { export type CustomFilter = {
numComments: number; numComments: number;
@ -29,7 +30,7 @@ export type FilterOption<T> = {
export type Filter = { export type Filter = {
id: FilterId; id: FilterId;
label: string; label: FilterLabel;
options: Array<FilterOption<FilterValue>>; options: Array<FilterOption<FilterValue>>;
}; };

Loading…
Cancel
Save