mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2026-04-29 21:12:37 +08:00
[resumes][feat] migrate to use location db and role enum (#506)
* [resumes][feat] use role and countries typeaheads * [resumes][feat] add location and role typeaheads * [resumes][chore] locationId migration * [resumes][fix] update upsert to take in locationId * [resumes][refactor] use typeahead for browse filters * [resumes][feat] use role and countries typeaheads * [resumes][chore] locationId migration * [resumes][feat] fetch location on resumes page * [resumes][feat] enable edit resume form * [resumes][misc] update namings and oredrings * [resumes][feat] add default locations * [resumes][fix] truncate title text in resume card * [resumes][fix] filter out selected options * [resumes][feat] add more countries to default search * [resumes][feat] update default roles * [resumes][chore] revert removal of value * [resumes]feat] add default location for migration file * [resumes][fix] fix merge conflicts Co-authored-by: Wu Peirong <wupeirong294@gmail.com>
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
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';
|
||||
@@ -35,7 +33,7 @@ export const resumesRouter = createRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
@@ -49,6 +47,11 @@ export const resumesRouter = createRouter()
|
||||
},
|
||||
},
|
||||
comments: true,
|
||||
location: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
stars: {
|
||||
where: {
|
||||
OR: {
|
||||
@@ -79,7 +82,7 @@ export const resumesRouter = createRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
@@ -92,7 +95,8 @@ export const resumesRouter = createRouter()
|
||||
id: r.id,
|
||||
isResolved: r.isResolved,
|
||||
isStarredByUser: r.stars.length > 0,
|
||||
location: r.location,
|
||||
location: r.location.name,
|
||||
locationId: r.locationId,
|
||||
numComments: r._count.comments,
|
||||
numStars: r._count.stars,
|
||||
role: r.role,
|
||||
@@ -103,7 +107,7 @@ export const resumesRouter = createRouter()
|
||||
return resume;
|
||||
});
|
||||
|
||||
// Group by role and count, taking into account all role/experience/location/isUnreviewed filters and search value
|
||||
// Group by role and count, taking into account all role/experience/locationId/isUnreviewed filters and search value
|
||||
const roleCounts = await ctx.prisma.resumesResume.groupBy({
|
||||
_count: {
|
||||
_all: true,
|
||||
@@ -112,7 +116,7 @@ export const resumesRouter = createRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
});
|
||||
@@ -122,20 +126,6 @@ export const resumesRouter = createRouter()
|
||||
roleCounts.map((rc) => [rc.role, rc._count._all]),
|
||||
);
|
||||
|
||||
// Filter out roles with zero counts and map to object where key = role and value = 0
|
||||
const zeroRoleCounts = Object.fromEntries(
|
||||
ROLES.filter((r) => !(r.value in mappedRoleCounts)).map((r) => [
|
||||
r.value,
|
||||
0,
|
||||
]),
|
||||
);
|
||||
|
||||
// Combine to form singular role counts object
|
||||
const processedRoleCounts = {
|
||||
...mappedRoleCounts,
|
||||
...zeroRoleCounts,
|
||||
};
|
||||
|
||||
const experienceCounts = await ctx.prisma.resumesResume.groupBy({
|
||||
_count: {
|
||||
_all: true,
|
||||
@@ -143,7 +133,7 @@ export const resumesRouter = createRouter()
|
||||
by: ['experience'],
|
||||
where: {
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
@@ -151,21 +141,12 @@ export const resumesRouter = createRouter()
|
||||
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'],
|
||||
by: ['locationId'],
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
@@ -174,23 +155,13 @@ export const resumesRouter = createRouter()
|
||||
},
|
||||
});
|
||||
const mappedLocationCounts = Object.fromEntries(
|
||||
locationCounts.map((lc) => [lc.location, lc._count._all]),
|
||||
locationCounts.map((lc) => [lc.locationId, lc._count._all]),
|
||||
);
|
||||
const zeroLocationCounts = Object.fromEntries(
|
||||
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
|
||||
l.value,
|
||||
0,
|
||||
]),
|
||||
);
|
||||
const processedLocationCounts = {
|
||||
...mappedLocationCounts,
|
||||
...zeroLocationCounts,
|
||||
};
|
||||
|
||||
const filterCounts = {
|
||||
Experience: processedExperienceCounts,
|
||||
Location: processedLocationCounts,
|
||||
Role: processedRoleCounts,
|
||||
experience: mappedExperienceCounts,
|
||||
location: mappedLocationCounts,
|
||||
role: mappedRoleCounts,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -217,6 +188,11 @@ export const resumesRouter = createRouter()
|
||||
stars: true,
|
||||
},
|
||||
},
|
||||
location: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
stars: {
|
||||
where: {
|
||||
OR: {
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { EXPERIENCES, LOCATIONS, ROLES } from '~/utils/resumes/resumeFilters';
|
||||
|
||||
import { createProtectedRouter } from '../context';
|
||||
|
||||
import type { Resume } from '~/types/resume';
|
||||
|
||||
export const resumesResumeUserRouter = createProtectedRouter()
|
||||
.mutation('upsert', {
|
||||
// TODO: Use enums for experience, location, role
|
||||
input: z.object({
|
||||
additionalInfo: z.string().optional(),
|
||||
experience: z.string(),
|
||||
id: z.string().optional(),
|
||||
location: z.string(),
|
||||
locationId: z.string(),
|
||||
role: z.string(),
|
||||
title: z.string(),
|
||||
url: z.string(),
|
||||
@@ -25,7 +22,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
create: {
|
||||
additionalInfo: input.additionalInfo,
|
||||
experience: input.experience,
|
||||
location: input.location,
|
||||
locationId: input.locationId,
|
||||
role: input.role,
|
||||
title: input.title,
|
||||
url: input.url,
|
||||
@@ -34,7 +31,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
update: {
|
||||
additionalInfo: input.additionalInfo,
|
||||
experience: input.experience,
|
||||
location: input.location,
|
||||
locationId: input.locationId,
|
||||
role: input.role,
|
||||
title: input.title,
|
||||
url: input.url,
|
||||
@@ -91,7 +88,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
resume: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
@@ -108,6 +105,11 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
stars: true,
|
||||
},
|
||||
},
|
||||
location: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
select: {
|
||||
name: true,
|
||||
@@ -144,7 +146,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
resume: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
},
|
||||
@@ -160,7 +162,8 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
id: rs.resume.id,
|
||||
isResolved: rs.resume.isResolved,
|
||||
isStarredByUser: true,
|
||||
location: rs.resume.location,
|
||||
location: rs.resume.location.name,
|
||||
locationId: rs.resume.locationId,
|
||||
numComments: rs.resume._count.comments,
|
||||
numStars: rs.resume._count.stars,
|
||||
role: rs.resume.role,
|
||||
@@ -179,7 +182,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
stars: {
|
||||
some: {
|
||||
userId,
|
||||
@@ -191,16 +194,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
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: {
|
||||
@@ -209,7 +202,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
by: ['experience'],
|
||||
where: {
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
stars: {
|
||||
some: {
|
||||
@@ -222,21 +215,12 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
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'],
|
||||
by: ['locationId'],
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
@@ -250,23 +234,13 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
},
|
||||
});
|
||||
const mappedLocationCounts = Object.fromEntries(
|
||||
locationCounts.map((lc) => [lc.location, lc._count._all]),
|
||||
locationCounts.map((lc) => [lc.locationId, lc._count._all]),
|
||||
);
|
||||
const zeroLocationCounts = Object.fromEntries(
|
||||
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
|
||||
l.value,
|
||||
0,
|
||||
]),
|
||||
);
|
||||
const processedLocationCounts = {
|
||||
...mappedLocationCounts,
|
||||
...zeroLocationCounts,
|
||||
};
|
||||
|
||||
const filterCounts = {
|
||||
Experience: processedExperienceCounts,
|
||||
Location: processedLocationCounts,
|
||||
Role: processedRoleCounts,
|
||||
experience: mappedExperienceCounts,
|
||||
location: mappedLocationCounts,
|
||||
role: mappedRoleCounts,
|
||||
};
|
||||
|
||||
return { filterCounts, mappedResumeData, totalRecords };
|
||||
@@ -299,7 +273,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
userId,
|
||||
@@ -313,6 +287,11 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
stars: true,
|
||||
},
|
||||
},
|
||||
location: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
stars: {
|
||||
where: {
|
||||
userId,
|
||||
@@ -341,7 +320,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
userId,
|
||||
@@ -355,7 +334,8 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
id: r.id,
|
||||
isResolved: r.isResolved,
|
||||
isStarredByUser: r.stars.length > 0,
|
||||
location: r.location,
|
||||
location: r.location.name,
|
||||
locationId: r.locationId,
|
||||
numComments: r._count.comments,
|
||||
numStars: r._count.stars,
|
||||
role: r.role,
|
||||
@@ -374,7 +354,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
userId,
|
||||
},
|
||||
@@ -382,16 +362,6 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
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: {
|
||||
@@ -400,7 +370,7 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
by: ['experience'],
|
||||
where: {
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
location: { in: locationFilters },
|
||||
locationId: { in: locationFilters },
|
||||
role: { in: roleFilters },
|
||||
title: { contains: searchValue, mode: 'insensitive' },
|
||||
userId,
|
||||
@@ -409,21 +379,12 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
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'],
|
||||
by: ['locationId'],
|
||||
where: {
|
||||
experience: { in: experienceFilters },
|
||||
isResolved: isUnreviewed ? false : {},
|
||||
@@ -433,23 +394,13 @@ export const resumesResumeUserRouter = createProtectedRouter()
|
||||
},
|
||||
});
|
||||
const mappedLocationCounts = Object.fromEntries(
|
||||
locationCounts.map((lc) => [lc.location, lc._count._all]),
|
||||
locationCounts.map((lc) => [lc.locationId, lc._count._all]),
|
||||
);
|
||||
const zeroLocationCounts = Object.fromEntries(
|
||||
LOCATIONS.filter((l) => !(l.value in mappedLocationCounts)).map((l) => [
|
||||
l.value,
|
||||
0,
|
||||
]),
|
||||
);
|
||||
const processedLocationCounts = {
|
||||
...mappedLocationCounts,
|
||||
...zeroLocationCounts,
|
||||
};
|
||||
|
||||
const filterCounts = {
|
||||
Experience: processedExperienceCounts,
|
||||
Location: processedLocationCounts,
|
||||
Role: processedRoleCounts,
|
||||
experience: mappedExperienceCounts,
|
||||
location: mappedLocationCounts,
|
||||
role: mappedRoleCounts,
|
||||
};
|
||||
|
||||
return { filterCounts, mappedResumeData, totalRecords };
|
||||
|
||||
Reference in New Issue
Block a user