mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 04:33:42 +08:00
[resumes][feat] auto-resolve resume when comments >= 5
This commit is contained in:
@ -8,19 +8,30 @@ type Props = Readonly<{
|
||||
userId: string;
|
||||
}>;
|
||||
|
||||
const STALE_TIME = 60;
|
||||
|
||||
export default function ResumeUserBadges({ userId }: Props) {
|
||||
const userReviewedResumeCountQuery = trpc.useQuery([
|
||||
'resumes.resume.findUserReviewedResumeCount',
|
||||
{ userId },
|
||||
]);
|
||||
const userMaxResumeUpvoteCountQuery = trpc.useQuery([
|
||||
'resumes.resume.findUserMaxResumeUpvoteCount',
|
||||
{ userId },
|
||||
]);
|
||||
const userTopUpvotedCommentCountQuery = trpc.useQuery([
|
||||
'resumes.resume.findUserTopUpvotedCommentCount',
|
||||
{ userId },
|
||||
]);
|
||||
const userReviewedResumeCountQuery = trpc.useQuery(
|
||||
['resumes.resume.findUserReviewedResumeCount', { userId }],
|
||||
{
|
||||
retry: false,
|
||||
staleTime: STALE_TIME,
|
||||
},
|
||||
);
|
||||
const userMaxResumeUpvoteCountQuery = trpc.useQuery(
|
||||
['resumes.resume.findUserMaxResumeUpvoteCount', { userId }],
|
||||
{
|
||||
retry: false,
|
||||
staleTime: STALE_TIME,
|
||||
},
|
||||
);
|
||||
const userTopUpvotedCommentCountQuery = trpc.useQuery(
|
||||
['resumes.resume.findUserTopUpvotedCommentCount', { userId }],
|
||||
{
|
||||
retry: false,
|
||||
staleTime: STALE_TIME,
|
||||
},
|
||||
);
|
||||
|
||||
const payload: BadgePayload = {
|
||||
maxResumeUpvoteCount: userMaxResumeUpvoteCountQuery.data ?? 0,
|
||||
|
@ -34,7 +34,18 @@ export default function ResumeListItem({ href, resumeInfo }: Props) {
|
||||
<div className="grid grid-cols-8">
|
||||
<div className="col-span-7 grid gap-4 border-b border-slate-200 p-4 hover:bg-slate-100 sm:grid-cols-7">
|
||||
<div className="sm:col-span-4">
|
||||
{resumeInfo.title}
|
||||
<div className="flex items-center gap-3">
|
||||
<p>{resumeInfo.title}</p>
|
||||
{resumeInfo.isResolved ? (
|
||||
<p className="rounded-xl border border-slate-200 p-1 text-xs text-slate-300">
|
||||
Reviewed
|
||||
</p>
|
||||
) : (
|
||||
<p className="rounded-xl border border-slate-400 p-1 text-xs text-slate-500">
|
||||
Unreviewed
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-primary-500 mt-2 flex items-center justify-start text-xs">
|
||||
<div className="flex">
|
||||
<BriefcaseIcon
|
||||
|
@ -53,18 +53,38 @@ export default function ResumeCommentsForm({
|
||||
},
|
||||
},
|
||||
);
|
||||
const invalidateResumeQueries = () => {
|
||||
trpcContext.invalidateQueries(['resumes.resume.findOne']);
|
||||
trpcContext.invalidateQueries(['resumes.resume.findAll']);
|
||||
trpcContext.invalidateQueries(['resumes.resume.user.findUserStarred']);
|
||||
trpcContext.invalidateQueries(['resumes.resume.user.findUserCreated']);
|
||||
};
|
||||
|
||||
const resolveMutation = trpc.useMutation('resumes.resume.user.resolve', {
|
||||
onSuccess() {
|
||||
invalidateResumeQueries();
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Give a feedback to the user if the action succeeds/fails
|
||||
const onSubmit: SubmitHandler<IFormInput> = async (data) => {
|
||||
const onSubmit: SubmitHandler<IFormInput> = async (formData) => {
|
||||
return await commentCreateMutation.mutate(
|
||||
{
|
||||
resumeId,
|
||||
...data,
|
||||
...formData,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
onSuccess: (data) => {
|
||||
// Redirect back to comments section
|
||||
setShowCommentsForm(false);
|
||||
const { prevCount, newCount } = data;
|
||||
// Auto mark resume as resolved once the total comments passes the 5 threshold
|
||||
if (newCount >= 5 && prevCount < 5) {
|
||||
resolveMutation.mutate({
|
||||
id: resumeId,
|
||||
val: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
@ -471,6 +471,7 @@ export default function ResumeHomePage() {
|
||||
<main className="h-full flex-auto px-8 pb-4">
|
||||
<div className="flex justify-start">
|
||||
<div className="fixed top-0 bottom-0 mt-24 hidden w-64 overflow-auto lg:block">
|
||||
{/* Quick Access Section */}
|
||||
<h3 className="text-md font-medium tracking-tight text-gray-900">
|
||||
Quick access
|
||||
</h3>
|
||||
@ -489,6 +490,7 @@ export default function ResumeHomePage() {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{/* Filter Section */}
|
||||
<h3 className="text-md font-medium tracking-tight text-slate-900">
|
||||
Explore these filters
|
||||
</h3>
|
||||
|
@ -45,9 +45,19 @@ export const resumesCommentsUserRouter = createProtectedRouter()
|
||||
};
|
||||
});
|
||||
|
||||
return await ctx.prisma.resumesComment.createMany({
|
||||
const prevCommentCount = await ctx.prisma.resumesComment.count({
|
||||
where: {
|
||||
resumeId,
|
||||
},
|
||||
});
|
||||
const result = await ctx.prisma.resumesComment.createMany({
|
||||
data: comments,
|
||||
});
|
||||
|
||||
return {
|
||||
newCount: Number(prevCommentCount) + result.count,
|
||||
prevCount: prevCommentCount,
|
||||
};
|
||||
},
|
||||
})
|
||||
.mutation('update', {
|
||||
|
Reference in New Issue
Block a user