diff --git a/apps/portal/src/server/router/index.ts b/apps/portal/src/server/router/index.ts index 94eecbe8..878ec632 100644 --- a/apps/portal/src/server/router/index.ts +++ b/apps/portal/src/server/router/index.ts @@ -3,6 +3,7 @@ import superjson from 'superjson'; import { companiesRouter } from './companies-router'; import { createRouter } from './context'; import { protectedExampleRouter } from './protected-example-router'; +import { questionsAnswerRouter } from './questions-answer-router'; import { questionsQuestionCommentRouter } from './questions-question-comment-router'; import { questionsQuestionRouter } from './questions-question-router'; import { resumesRouter } from './resumes/resumes-resume-router'; @@ -27,6 +28,7 @@ export const appRouter = createRouter() .merge('resumes.star.user.', resumesStarUserRouter) .merge('resumes.reviews.', resumeReviewsRouter) .merge('resumes.reviews.user.', resumesReviewsUserRouter) + .merge('questions.answers.', questionsAnswerRouter) .merge('questions.questions.comments.', questionsQuestionCommentRouter) .merge('questions.questions.', questionsQuestionRouter); diff --git a/apps/portal/src/server/router/questions-answer-router.ts b/apps/portal/src/server/router/questions-answer-router.ts new file mode 100644 index 00000000..61a5b6c5 --- /dev/null +++ b/apps/portal/src/server/router/questions-answer-router.ts @@ -0,0 +1,235 @@ +import { z } from 'zod'; +import { Vote } from '@prisma/client'; +import { TRPCError } from '@trpc/server'; + +import { createProtectedRouter } from './context'; + +import type { Answer } from '~/types/questions'; + +export const questionsAnswerRouter = createProtectedRouter() + .query('getAnswers', { + input: z.object({ + questionId: z.string(), + }), + async resolve({ ctx, input }) { + const answersData = await ctx.prisma.questionsAnswer.findMany({ + include: { + _count: { + select: { + comments: true, + }, + }, + user: { + select: { + name: true, + }, + }, + votes: true, + }, + orderBy: { + createdAt: 'desc', + }, + where: { + ...input, + }, + }); + return answersData.map((data) => { + const votes:number = data.votes.reduce( + (previousValue:number, currentValue) => { + let result:number = previousValue; + + switch(currentValue.vote) { + case Vote.UPVOTE: + result += 1 + break; + case Vote.DOWNVOTE: + result -= 1 + break; + } + return result; + }, + 0 + ); + + let userName = ""; + + if (data.user) { + userName = data.user.name!; + } + + + const answer: Answer = { + content: data.content, + createdAt: data.createdAt, + id: data.id, + numComments: data._count.comments, + numVotes: votes, + user: userName, + }; + return answer; + }); + } + }) + .mutation('create', { + input: z.object({ + content: z.string(), + questionId: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + + return await ctx.prisma.questionsAnswer.create({ + data: { + ...input, + userId, + }, + }); + }, + }) + .mutation('update', { + input: z.object({ + content: z.string().optional(), + id: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + const {content, id} = input + + const answerToUpdate = await ctx.prisma.questionsAnswer.findUnique({ + where: { + id: input.id, + }, + }); + + if (answerToUpdate?.id !== userId) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'User have no authorization to record.', + }); + } + + return await ctx.prisma.questionsAnswer.update({ + data: { + content, + }, + where: { + id, + }, + }); + }, + }) + .mutation('delete', { + input: z.object({ + id: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + + const answerToDelete = await ctx.prisma.questionsAnswer.findUnique({ + where: { + id: input.id, + },}); + + if (answerToDelete?.id !== userId) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'User have no authorization to record.', + }); + } + + return await ctx.prisma.questionsAnswer.delete({ + where: { + id: input.id, + }, + }); + }, + }) + .query('getVote', { + input: z.object({ + answerId: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + const {answerId} = input + + return await ctx.prisma.questionsAnswerVote.findUnique({ + where: { + answerId_userId : { answerId, userId }, + }, + }); + }, + }) + .mutation('createVote', { + input: z.object({ + answerId: z.string(), + vote: z.nativeEnum(Vote), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + + return await ctx.prisma.questionsAnswerVote.create({ + data: { + ...input, + userId, + }, + }); + }, + }) + .mutation('updateVote', { + input: z.object({ + id: z.string(), + vote: z.nativeEnum(Vote), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + const {id, vote} = input + + const voteToUpdate = await ctx.prisma.questionsAnswerVote.findUnique({ + where: { + id: input.id, + }, + }); + + if (voteToUpdate?.id !== userId) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'User have no authorization to record.', + }); + } + + return await ctx.prisma.questionsAnswerVote.update({ + data: { + vote, + }, + where: { + id, + }, + }); + }, + }) + .mutation('deleteVote', { + input: z.object({ + id: z.string(), + }), + async resolve({ ctx, input }) { + const userId = ctx.session?.user?.id; + + const voteToDelete = await ctx.prisma.questionsAnswerVote.findUnique({ + where: { + id: input.id, + },}); + + if (voteToDelete?.id !== userId) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'User have no authorization to record.', + }); + } + + return await ctx.prisma.questionsAnswerVote.delete({ + where: { + id: input.id, + }, + }); + }, + }); \ No newline at end of file diff --git a/apps/portal/src/types/questions.d.ts b/apps/portal/src/types/questions.d.ts index 633504ef..36aef367 100644 --- a/apps/portal/src/types/questions.d.ts +++ b/apps/portal/src/types/questions.d.ts @@ -12,9 +12,18 @@ export type Question = { user: string; }; +export type Answer = { + content: string; + createdAt: Date; + id: string; + numComments: number; + numVotes: number; +}; + export type QuestionComment = { content: string; createdAt: Date; id: string; numVotes: number; -}; \ No newline at end of file + user: string; +};