You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.1 KiB
170 lines
4.1 KiB
import { z } from 'zod';
|
|
import { Vote } from '@prisma/client';
|
|
import { TRPCError } from '@trpc/server';
|
|
|
|
import { createRouter } from '../context';
|
|
|
|
import type { Answer } from '~/types/questions';
|
|
import { SortOrder, SortType } from '~/types/questions.d';
|
|
|
|
export const questionsAnswerRouter = createRouter()
|
|
.query('getAnswers', {
|
|
input: z.object({
|
|
cursor: z.string().nullish(),
|
|
limit: z.number().min(1).default(50),
|
|
questionId: z.string(),
|
|
sortOrder: z.nativeEnum(SortOrder),
|
|
sortType: z.nativeEnum(SortType),
|
|
}),
|
|
async resolve({ ctx, input }) {
|
|
const { questionId, cursor } = input;
|
|
|
|
const sortCondition =
|
|
input.sortType === SortType.TOP
|
|
? [
|
|
{
|
|
upvotes: input.sortOrder,
|
|
},
|
|
{
|
|
id: input.sortOrder,
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
updatedAt: input.sortOrder,
|
|
},
|
|
{
|
|
id: input.sortOrder,
|
|
},
|
|
];
|
|
|
|
const answersData = await ctx.prisma.questionsAnswer.findMany({
|
|
cursor: cursor ? { id: cursor } : undefined,
|
|
include: {
|
|
_count: {
|
|
select: {
|
|
comments: true,
|
|
},
|
|
},
|
|
user: {
|
|
select: {
|
|
image: true,
|
|
name: true,
|
|
},
|
|
},
|
|
votes: true,
|
|
},
|
|
orderBy: sortCondition,
|
|
take: input.limit + 1,
|
|
where: {
|
|
questionId,
|
|
},
|
|
});
|
|
|
|
const processedAnswersData = 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,
|
|
);
|
|
|
|
const answer: Answer = {
|
|
content: data.content,
|
|
createdAt: data.createdAt,
|
|
id: data.id,
|
|
numComments: data._count.comments,
|
|
numVotes: votes,
|
|
user: data.user?.name ?? '',
|
|
userImage: data.user?.image ?? '',
|
|
};
|
|
return answer;
|
|
});
|
|
|
|
let nextCursor: typeof cursor | undefined = undefined;
|
|
|
|
if (answersData.length > input.limit) {
|
|
const nextItem = answersData.pop()!;
|
|
processedAnswersData.pop();
|
|
|
|
const nextIdCursor: string | undefined = nextItem.id;
|
|
|
|
nextCursor = nextIdCursor;
|
|
}
|
|
|
|
return {
|
|
data: processedAnswersData,
|
|
nextCursor,
|
|
};
|
|
},
|
|
})
|
|
.query('getAnswerById', {
|
|
input: z.object({
|
|
answerId: z.string(),
|
|
}),
|
|
async resolve({ ctx, input }) {
|
|
const answerData = await ctx.prisma.questionsAnswer.findUnique({
|
|
include: {
|
|
_count: {
|
|
select: {
|
|
comments: true,
|
|
},
|
|
},
|
|
user: {
|
|
select: {
|
|
image: true,
|
|
name: true,
|
|
},
|
|
},
|
|
votes: true,
|
|
},
|
|
where: {
|
|
id: input.answerId,
|
|
},
|
|
});
|
|
if (!answerData) {
|
|
throw new TRPCError({
|
|
code: 'NOT_FOUND',
|
|
message: 'Answer not found',
|
|
});
|
|
}
|
|
const votes: number = answerData.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,
|
|
);
|
|
|
|
const answer: Answer = {
|
|
content: answerData.content,
|
|
createdAt: answerData.createdAt,
|
|
id: answerData.id,
|
|
numComments: answerData._count.comments,
|
|
numVotes: votes,
|
|
user: answerData.user?.name ?? '',
|
|
userImage: answerData.user?.image ?? '',
|
|
};
|
|
return answer;
|
|
},
|
|
});
|