[questions][fix] fix upvotes (#521)
parent
ffbb6a29f2
commit
a7c9f58ef3
@ -0,0 +1,28 @@
|
||||
import useAnswerCommentVote from '~/utils/questions/vote/useAnswerCommentVote';
|
||||
|
||||
import type { CommentListItemProps } from './CommentListItem';
|
||||
import CommentListItem from './CommentListItem';
|
||||
|
||||
export type AnswerCommentListItemProps = Omit<
|
||||
CommentListItemProps,
|
||||
'onDownvote' | 'onUpvote' | 'vote'
|
||||
> & {
|
||||
answerCommentId: string;
|
||||
};
|
||||
|
||||
export default function AnswerCommentListItem({
|
||||
answerCommentId,
|
||||
...restProps
|
||||
}: AnswerCommentListItemProps) {
|
||||
const { handleDownvote, handleUpvote, vote } =
|
||||
useAnswerCommentVote(answerCommentId);
|
||||
|
||||
return (
|
||||
<CommentListItem
|
||||
vote={vote}
|
||||
onDownvote={handleDownvote}
|
||||
onUpvote={handleUpvote}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,37 +1,37 @@
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import { useAnswerCommentVote } from '~/utils/questions/useVote';
|
||||
import type { BackendVote } from '../VotingButtons';
|
||||
import VotingButtons from '../VotingButtons';
|
||||
|
||||
import VotingButtons from './VotingButtons';
|
||||
|
||||
export type AnswerCommentListItemProps = {
|
||||
answerCommentId: string;
|
||||
export type CommentListItemProps = {
|
||||
authorImageUrl: string;
|
||||
authorName: string;
|
||||
content: string;
|
||||
createdAt: Date;
|
||||
onDownvote: () => void;
|
||||
onUpvote: () => void;
|
||||
upvoteCount: number;
|
||||
vote: BackendVote;
|
||||
};
|
||||
|
||||
export default function AnswerCommentListItem({
|
||||
export default function CommentListItem({
|
||||
authorImageUrl,
|
||||
authorName,
|
||||
content,
|
||||
createdAt,
|
||||
upvoteCount,
|
||||
answerCommentId,
|
||||
}: AnswerCommentListItemProps) {
|
||||
const { handleDownvote, handleUpvote, vote } =
|
||||
useAnswerCommentVote(answerCommentId);
|
||||
|
||||
vote,
|
||||
onDownvote,
|
||||
onUpvote,
|
||||
}: CommentListItemProps) {
|
||||
return (
|
||||
<div className="flex gap-4 rounded-md border bg-white p-2">
|
||||
<VotingButtons
|
||||
size="sm"
|
||||
upvoteCount={upvoteCount}
|
||||
vote={vote}
|
||||
onDownvote={handleDownvote}
|
||||
onUpvote={handleUpvote}
|
||||
onDownvote={onDownvote}
|
||||
onUpvote={onUpvote}
|
||||
/>
|
||||
<div className="mt-1 flex flex-col gap-1">
|
||||
<div className="flex items-center gap-2">
|
@ -0,0 +1,28 @@
|
||||
import useQuestionCommentVote from '~/utils/questions/vote/useQuestionCommentVote';
|
||||
|
||||
import type { CommentListItemProps } from './CommentListItem';
|
||||
import CommentListItem from './CommentListItem';
|
||||
|
||||
export type QuestionCommentListItemProps = Omit<
|
||||
CommentListItemProps,
|
||||
'onDownvote' | 'onUpvote' | 'vote'
|
||||
> & {
|
||||
questionCommentId: string;
|
||||
};
|
||||
|
||||
export default function QuestionCommentListItem({
|
||||
questionCommentId,
|
||||
...restProps
|
||||
}: QuestionCommentListItemProps) {
|
||||
const { handleDownvote, handleUpvote, vote } =
|
||||
useQuestionCommentVote(questionCommentId);
|
||||
|
||||
return (
|
||||
<CommentListItem
|
||||
vote={vote}
|
||||
onDownvote={handleDownvote}
|
||||
onUpvote={handleUpvote}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import type { InfiniteData } from 'react-query';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
import useVote from './useVote';
|
||||
|
||||
import type { AnswerComment } from '~/types/questions';
|
||||
|
||||
export default function useAnswerCommentVote(id: string) {
|
||||
const utils = trpc.useContext();
|
||||
|
||||
return useVote(id, {
|
||||
idKey: 'answerCommentId',
|
||||
invalidateKeys: [],
|
||||
onMutate: async (voteValueChange) => {
|
||||
// Update answer comment list
|
||||
const answerCommentQueries = utils.queryClient.getQueriesData([
|
||||
'questions.answers.comments.getAnswerComments',
|
||||
]);
|
||||
|
||||
const revertFunctions: Array<() => void> = [];
|
||||
|
||||
if (answerCommentQueries !== undefined) {
|
||||
for (const [key, query] of answerCommentQueries) {
|
||||
if (query === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { pages, ...restQuery } = query as InfiniteData<{
|
||||
data: Array<AnswerComment>;
|
||||
}>;
|
||||
|
||||
const newQuery = {
|
||||
pages: pages.map(({ data, ...restPage }) => ({
|
||||
data: data.map((answerComment) => {
|
||||
if (answerComment.id === id) {
|
||||
const { numVotes, ...restAnswerComment } = answerComment;
|
||||
return {
|
||||
numVotes: numVotes + voteValueChange,
|
||||
...restAnswerComment,
|
||||
};
|
||||
}
|
||||
return answerComment;
|
||||
}),
|
||||
...restPage,
|
||||
})),
|
||||
...restQuery,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(key, newQuery);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(key, query);
|
||||
});
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
for (const revertFunction of revertFunctions) {
|
||||
revertFunction();
|
||||
}
|
||||
};
|
||||
},
|
||||
query: 'questions.answers.comments.user.getVote',
|
||||
setDownVoteKey: 'questions.answers.comments.user.setDownVote',
|
||||
setNoVoteKey: 'questions.answers.comments.user.setNoVote',
|
||||
setUpVoteKey: 'questions.answers.comments.user.setUpVote',
|
||||
});
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
import type { InfiniteData } from 'react-query';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
import useVote from './useVote';
|
||||
|
||||
import type { Answer } from '~/types/questions';
|
||||
|
||||
export default function useAnswerVote(id: string) {
|
||||
const utils = trpc.useContext();
|
||||
|
||||
return useVote(id, {
|
||||
idKey: 'answerId',
|
||||
invalidateKeys: [
|
||||
// 'questions.answers.getAnswerById',
|
||||
// 'questions.answers.getAnswers',
|
||||
],
|
||||
onMutate: async (voteValueChange) => {
|
||||
// Update question answer list
|
||||
const answerQueries = utils.queryClient.getQueriesData([
|
||||
'questions.answers.getAnswers',
|
||||
]);
|
||||
|
||||
const revertFunctions: Array<() => void> = [];
|
||||
|
||||
if (answerQueries !== undefined) {
|
||||
for (const [key, query] of answerQueries) {
|
||||
if (query === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { pages, ...restQuery } = query as InfiniteData<{
|
||||
data: Array<Answer>;
|
||||
}>;
|
||||
|
||||
const newQuery = {
|
||||
pages: pages.map(({ data, ...restPage }) => ({
|
||||
data: data.map((answer) => {
|
||||
if (answer.id === id) {
|
||||
const { numVotes, ...restAnswer } = answer;
|
||||
return {
|
||||
numVotes: numVotes + voteValueChange,
|
||||
...restAnswer,
|
||||
};
|
||||
}
|
||||
return answer;
|
||||
}),
|
||||
...restPage,
|
||||
})),
|
||||
...restQuery,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(key, newQuery);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(key, query);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const prevAnswer = utils.queryClient.getQueryData([
|
||||
'questions.answers.getAnswerById',
|
||||
{
|
||||
answerId: id,
|
||||
},
|
||||
]) as Answer | undefined;
|
||||
|
||||
if (prevAnswer !== undefined) {
|
||||
const newAnswer = {
|
||||
...prevAnswer,
|
||||
numVotes: prevAnswer.numVotes + voteValueChange,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(
|
||||
['questions.answers.getAnswerById', { answerId: id }],
|
||||
newAnswer,
|
||||
);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(
|
||||
['questions.answers.getAnswerById', { answerId: id }],
|
||||
prevAnswer,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
for (const revertFunction of revertFunctions) {
|
||||
revertFunction();
|
||||
}
|
||||
};
|
||||
},
|
||||
query: 'questions.answers.user.getVote',
|
||||
setDownVoteKey: 'questions.answers.user.setDownVote',
|
||||
setNoVoteKey: 'questions.answers.user.setNoVote',
|
||||
setUpVoteKey: 'questions.answers.user.setUpVote',
|
||||
});
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
import type { InfiniteData } from 'react-query';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
import useVote from './useVote';
|
||||
|
||||
import type { QuestionComment } from '~/types/questions';
|
||||
|
||||
export default function useQuestionCommentVote(id: string) {
|
||||
const utils = trpc.useContext();
|
||||
|
||||
return useVote(id, {
|
||||
idKey: 'questionCommentId',
|
||||
invalidateKeys: [],
|
||||
onMutate: async (voteValueChange) => {
|
||||
// Update question comment list
|
||||
const questionCommentQueries = utils.queryClient.getQueriesData([
|
||||
'questions.questions.comments.getQuestionComments',
|
||||
]);
|
||||
|
||||
const revertFunctions: Array<() => void> = [];
|
||||
|
||||
if (questionCommentQueries !== undefined) {
|
||||
for (const [key, query] of questionCommentQueries) {
|
||||
if (query === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { pages, ...restQuery } = query as InfiniteData<{
|
||||
data: Array<QuestionComment>;
|
||||
}>;
|
||||
|
||||
const newQuery = {
|
||||
pages: pages.map(({ data, ...restPage }) => ({
|
||||
data: data.map((questionComment) => {
|
||||
if (questionComment.id === id) {
|
||||
const { numVotes, ...restQuestionComment } = questionComment;
|
||||
return {
|
||||
numVotes: numVotes + voteValueChange,
|
||||
...restQuestionComment,
|
||||
};
|
||||
}
|
||||
return questionComment;
|
||||
}),
|
||||
...restPage,
|
||||
})),
|
||||
...restQuery,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(key, newQuery);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(key, query);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
for (const revertFunction of revertFunctions) {
|
||||
revertFunction();
|
||||
}
|
||||
};
|
||||
},
|
||||
query: 'questions.questions.comments.user.getVote',
|
||||
setDownVoteKey: 'questions.questions.comments.user.setDownVote',
|
||||
setNoVoteKey: 'questions.questions.comments.user.setNoVote',
|
||||
setUpVoteKey: 'questions.questions.comments.user.setUpVote',
|
||||
});
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
import type { InfiniteData } from 'react-query';
|
||||
|
||||
import { trpc } from '~/utils/trpc';
|
||||
|
||||
import useVote from './useVote';
|
||||
|
||||
import type { Question } from '~/types/questions';
|
||||
|
||||
export const useQuestionVote = (id: string) => {
|
||||
const utils = trpc.useContext();
|
||||
|
||||
return useVote(id, {
|
||||
idKey: 'questionId',
|
||||
invalidateKeys: [
|
||||
// 'questions.questions.getQuestionById',
|
||||
// 'questions.questions.getQuestionsByFilterAndContent',
|
||||
],
|
||||
onMutate: async (voteValueChange) => {
|
||||
// Update question list
|
||||
const questionQueries = utils.queryClient.getQueriesData([
|
||||
'questions.questions.getQuestionsByFilterAndContent',
|
||||
]);
|
||||
|
||||
const revertFunctions: Array<() => void> = [];
|
||||
|
||||
if (questionQueries !== undefined) {
|
||||
for (const [key, query] of questionQueries) {
|
||||
if (query === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { pages, ...restQuery } = query as InfiniteData<{
|
||||
data: Array<Question>;
|
||||
}>;
|
||||
|
||||
const newQuery = {
|
||||
pages: pages.map(({ data, ...restPage }) => ({
|
||||
data: data.map((question) => {
|
||||
if (question.id === id) {
|
||||
const { numVotes, ...restQuestion } = question;
|
||||
return {
|
||||
numVotes: numVotes + voteValueChange,
|
||||
...restQuestion,
|
||||
};
|
||||
}
|
||||
return question;
|
||||
}),
|
||||
...restPage,
|
||||
})),
|
||||
...restQuery,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(key, newQuery);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(key, query);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const prevQuestion = utils.queryClient.getQueryData([
|
||||
'questions.questions.getQuestionById',
|
||||
{
|
||||
id,
|
||||
},
|
||||
]) as Question | undefined;
|
||||
|
||||
if (prevQuestion !== undefined) {
|
||||
const newQuestion = {
|
||||
...prevQuestion,
|
||||
numVotes: prevQuestion.numVotes + voteValueChange,
|
||||
};
|
||||
|
||||
utils.queryClient.setQueryData(
|
||||
['questions.questions.getQuestionById', { id }],
|
||||
newQuestion,
|
||||
);
|
||||
|
||||
revertFunctions.push(() => {
|
||||
utils.queryClient.setQueryData(
|
||||
['questions.questions.getQuestionById', { id }],
|
||||
prevQuestion,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
for (const revertFunction of revertFunctions) {
|
||||
revertFunction();
|
||||
}
|
||||
};
|
||||
},
|
||||
query: 'questions.questions.user.getVote',
|
||||
setDownVoteKey: 'questions.questions.user.setDownVote',
|
||||
setNoVoteKey: 'questions.questions.user.setNoVote',
|
||||
setUpVoteKey: 'questions.questions.user.setUpVote',
|
||||
});
|
||||
};
|
Loading…
Reference in new issue