[resumes][refactor] abstract comment votes fetching from comments

pull/389/head
Terence Ho 3 years ago
parent 2900dbeb1a
commit 41963ef28b

@ -54,25 +54,32 @@ export default function ResumeCommentListItem({
},
},
);
const commentUpvoteUpsertMutation = trpc.useMutation(
'resumes.comments.upvotes.user.upsert',
// COMMENT VOTES
const commentVotesQuery = trpc.useQuery([
'resumes.comments.votes.list',
{ commentId: comment.id },
]);
const commentVotesUpsertMutation = trpc.useMutation(
'resumes.comments.votes.user.upsert',
{
onSuccess: () => {
// Comment updated, invalidate query to trigger refetch
trpcContext.invalidateQueries(['resumes.comments.list']);
trpcContext.invalidateQueries(['resumes.comments.votes.list']);
},
},
);
const commentUpvoteDeleteMutation = trpc.useMutation(
'resumes.comments.upvotes.user.delete',
const commentVotesDeleteMutation = trpc.useMutation(
'resumes.comments.votes.user.delete',
{
onSuccess: () => {
// Comment updated, invalidate query to trigger refetch
trpcContext.invalidateQueries(['resumes.comments.list']);
trpcContext.invalidateQueries(['resumes.comments.votes.list']);
},
},
);
// FORM ACTIONS
const onCancel = () => {
reset({ description: comment.description });
setIsEditingComment(false);
@ -98,14 +105,13 @@ export default function ResumeCommentListItem({
};
const onVote = async (value: Vote) => {
if (comment.userVote?.value === value) {
return commentUpvoteDeleteMutation.mutate({
if (commentVotesQuery.data?.userVote?.value === value) {
return commentVotesDeleteMutation.mutate({
commentId: comment.id,
});
}
return commentUpvoteUpsertMutation.mutate({
return commentVotesUpsertMutation.mutate({
commentId: comment.id,
id: comment.userVote?.id,
value,
});
};
@ -190,15 +196,16 @@ export default function ResumeCommentListItem({
<button
disabled={
!userId ||
commentUpvoteUpsertMutation.isLoading ||
commentUpvoteDeleteMutation.isLoading
commentVotesQuery.isLoading ||
commentVotesUpsertMutation.isLoading ||
commentVotesDeleteMutation.isLoading
}
type="button"
onClick={() => onVote(Vote.UPVOTE)}>
<ArrowUpCircleIcon
className={clsx(
'h-4 w-4',
comment.userVote?.value === Vote.UPVOTE
commentVotesQuery.data?.userVote?.value === Vote.UPVOTE
? 'fill-indigo-500'
: 'fill-gray-400',
userId && 'hover:fill-indigo-500',
@ -206,20 +213,23 @@ export default function ResumeCommentListItem({
/>
</button>
<div className="text-xs">{comment.numVotes}</div>
<div className="text-xs">
{commentVotesQuery.data?.numVotes ?? 0}
</div>
<button
disabled={
!userId ||
commentUpvoteUpsertMutation.isLoading ||
commentUpvoteDeleteMutation.isLoading
commentVotesQuery.isLoading ||
commentVotesUpsertMutation.isLoading ||
commentVotesDeleteMutation.isLoading
}
type="button"
onClick={() => onVote(Vote.DOWNVOTE)}>
<ArrowDownCircleIcon
className={clsx(
'h-4 w-4',
comment.userVote?.value === Vote.DOWNVOTE
commentVotesQuery.data?.userVote?.value === Vote.DOWNVOTE
? 'fill-red-500'
: 'fill-gray-400',
userId && 'hover:fill-red-500',

@ -12,8 +12,9 @@ import { questionsAnswerRouter } from './questions-answer-router';
import { questionsQuestionCommentRouter } from './questions-question-comment-router';
import { questionsQuestionRouter } from './questions-question-router';
import { resumeCommentsRouter } from './resumes/resumes-comments-router';
import { resumesCommentsUpvotesUserRouter } from './resumes/resumes-comments-upvotes-user-router';
import { resumesCommentsUserRouter } from './resumes/resumes-comments-user-router';
import { resumesCommentsVotesRouter } from './resumes/resumes-comments-votes-router';
import { resumesCommentsVotesUserRouter } from './resumes/resumes-comments-votes-user-router';
import { resumesRouter } from './resumes/resumes-resume-router';
import { resumesResumeUserRouter } from './resumes/resumes-resume-user-router';
import { resumesStarUserRouter } from './resumes/resumes-star-user-router';
@ -34,7 +35,8 @@ export const appRouter = createRouter()
.merge('resumes.resume.', resumesStarUserRouter)
.merge('resumes.comments.', resumeCommentsRouter)
.merge('resumes.comments.user.', resumesCommentsUserRouter)
.merge('resumes.comments.upvotes.user.', resumesCommentsUpvotesUserRouter)
.merge('resumes.comments.votes.', resumesCommentsVotesRouter)
.merge('resumes.comments.votes.user.', resumesCommentsVotesUserRouter)
.merge('questions.answers.comments.', questionsAnswerCommentRouter)
.merge('questions.answers.', questionsAnswerRouter)
.merge('questions.questions.comments.', questionsQuestionCommentRouter)

@ -1,6 +1,4 @@
import { z } from 'zod';
import type { ResumesCommentVote } from '@prisma/client';
import { Vote } from '@prisma/client';
import { createRouter } from '../context';
@ -11,7 +9,6 @@ export const resumeCommentsRouter = createRouter().query('list', {
resumeId: z.string(),
}),
async resolve({ ctx, input }) {
const userId = ctx.session?.user?.id;
const { resumeId } = input;
// For this resume, we retrieve every comment's information, along with:
@ -36,19 +33,10 @@ export const resumeCommentsRouter = createRouter().query('list', {
});
return comments.map((data) => {
let userVote: ResumesCommentVote | undefined = undefined;
let numVotes = 0;
data.votes.forEach((vote) => {
numVotes += vote.value === Vote.UPVOTE ? 1 : -1;
userVote = vote.userId === userId ? vote : undefined;
});
const comment: ResumeComment = {
createdAt: data.createdAt,
description: data.description,
id: data.id,
numVotes,
resumeId: data.resumeId,
section: data.section,
updatedAt: data.updatedAt,
@ -57,7 +45,6 @@ export const resumeCommentsRouter = createRouter().query('list', {
name: data.user.name,
userId: data.userId,
},
userVote,
};
return comment;

@ -0,0 +1,38 @@
import { z } from 'zod';
import type { ResumesCommentVote } from '@prisma/client';
import { Vote } from '@prisma/client';
import { createRouter } from '../context';
import type { ResumeCommentVote } from '~/types/resume-comments';
export const resumesCommentsVotesRouter = createRouter().query('list', {
input: z.object({
commentId: z.string(),
}),
async resolve({ ctx, input }) {
const userId = ctx.session?.user?.id;
const { commentId } = input;
const votes = await ctx.prisma.resumesCommentVote.findMany({
where: {
commentId,
},
});
let userVote: ResumesCommentVote | null = null;
let numVotes = 0;
votes.forEach((vote) => {
numVotes += vote.value === Vote.UPVOTE ? 1 : -1;
userVote = vote.userId === userId ? vote : null;
});
const resumeCommentVote: ResumeCommentVote = {
numVotes,
userVote,
};
return resumeCommentVote;
},
});

@ -3,16 +3,15 @@ import { Vote } from '@prisma/client';
import { createProtectedRouter } from '../context';
export const resumesCommentsUpvotesUserRouter = createProtectedRouter()
export const resumesCommentsVotesUserRouter = createProtectedRouter()
.mutation('upsert', {
input: z.object({
commentId: z.string(),
id: z.string().optional(),
value: z.nativeEnum(Vote),
}),
async resolve({ ctx, input }) {
const userId = ctx.session.user.id;
const { id, commentId, value } = input;
const { commentId, value } = input;
await ctx.prisma.resumesCommentVote.upsert({
create: {
@ -21,9 +20,6 @@ export const resumesCommentsUpvotesUserRouter = createProtectedRouter()
value,
},
update: {
commentId,
id,
userId,
value,
},
where: {

@ -8,7 +8,6 @@ export type ResumeComment = Readonly<{
createdAt: Date;
description: string;
id: string;
numVotes: number;
resumeId: string;
section: ResumesSection;
updatedAt: Date;
@ -17,5 +16,9 @@ export type ResumeComment = Readonly<{
name: string?;
userId: string;
};
userVote: ResumesCommentVote | undefined;
}>;
export type ResumeCommentVote = Readonly<{
numVotes: number;
userVote: ResumesCommentVote?;
}>;

Loading…
Cancel
Save