Skip to content

Commit 42ff3b2

Browse files
committed
fix: ensure posts and comments display correct score after user votes
1 parent 86c7fc6 commit 42ff3b2

File tree

2 files changed

+57
-28
lines changed

2 files changed

+57
-28
lines changed

src/app/(ui)/vote/VoteButtons.tsx

+54-26
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,46 @@ type BaseProps = {
1212
voteConfig: VoteConfig;
1313
loggedInUserScore?: number;
1414
score?: number;
15+
onScoreChange?(newScore: number): void;
1516
};
1617

1718
type CommentProps = BaseProps & { commentId: number; postId: number };
1819
type PostProps = BaseProps & { postId: number };
1920

2021
type Props = CommentProps | PostProps;
22+
23+
const getNewScore = (
24+
prevScore: number | undefined,
25+
prevUserScore: number | undefined,
26+
newUserScore: number,
27+
) => {
28+
let newScore = prevScore ?? 0;
29+
if (newScore) {
30+
newScore = newScore - (prevUserScore ?? 0) + newUserScore;
31+
}
32+
33+
return newScore;
34+
};
35+
2136
export const VoteButtons = memo(
2237
(props: Props) => {
23-
const totalScore = !isComment(props) ? props.score : undefined; // We only show score between vote buttons for posts, not comments
24-
const [userScore, setUserScore] = useState(props.loggedInUserScore);
38+
const [score, setScore] = useState({
39+
userScore: props.loggedInUserScore,
40+
totalScore: props.score,
41+
});
2542

2643
const [{ optimisticUserScore, optimisticScore }, setOptimisticUserScore] =
2744
useOptimistic(
28-
{ optimisticUserScore: userScore, optimisticScore: totalScore },
45+
{
46+
optimisticUserScore: score.userScore ?? 0,
47+
optimisticScore: score.totalScore ?? 0,
48+
},
2949
(prevState, newUserScore: number) => {
30-
let newScore = prevState.optimisticScore;
31-
if (newScore) {
32-
newScore =
33-
newScore - (prevState.optimisticUserScore ?? 0) + newUserScore;
34-
}
50+
let newScore = getNewScore(
51+
prevState.optimisticScore,
52+
prevState.optimisticUserScore,
53+
newUserScore,
54+
);
3555

3656
return {
3757
optimisticUserScore: newUserScore,
@@ -43,6 +63,29 @@ export const VoteButtons = memo(
4363
const upvoteResultScore = (optimisticUserScore ?? 0) <= 0 ? 1 : 0;
4464
const downvoteResultScore = (optimisticUserScore ?? 0) >= 0 ? -1 : 0;
4565

66+
const voteAction = async (userScoreAfterVoting: number) => {
67+
setOptimisticUserScore(userScoreAfterVoting);
68+
const action = isComment(props)
69+
? voteCommentAction.bind(null, props.commentId, userScoreAfterVoting)
70+
: votePostAction.bind(null, props.postId, userScoreAfterVoting);
71+
await action();
72+
setScore((prev) => {
73+
const newScore = getNewScore(
74+
prev.totalScore,
75+
prev.userScore,
76+
userScoreAfterVoting,
77+
);
78+
79+
if (props.onScoreChange) {
80+
props.onScoreChange(newScore ?? 0);
81+
}
82+
return {
83+
totalScore: newScore,
84+
userScore: userScoreAfterVoting,
85+
};
86+
});
87+
};
88+
4689
return (
4790
<div
4891
className={classNames(
@@ -52,13 +95,7 @@ export const VoteButtons = memo(
5295
>
5396
<form
5497
action={async () => {
55-
setOptimisticUserScore(upvoteResultScore);
56-
57-
const action = isComment(props)
58-
? voteCommentAction.bind(null, props.commentId, upvoteResultScore)
59-
: votePostAction.bind(null, props.postId, upvoteResultScore);
60-
await action();
61-
setUserScore(upvoteResultScore);
98+
await voteAction(upvoteResultScore);
6299
}}
63100
>
64101
<button type={"submit"}>
@@ -74,24 +111,15 @@ export const VoteButtons = memo(
74111
/>
75112
</button>
76113
</form>
77-
{optimisticScore !== undefined && props.voteConfig.scoresVisible && (
114+
{!isComment(props) && props.voteConfig.scoresVisible && (
78115
<div className={"mb-0.5 w-8 text-center font-semibold"}>
79116
{formatCompactNumber(optimisticScore)}
80117
</div>
81118
)}
82119
{props.voteConfig.downvotesEnabled && (
83120
<form
84121
action={async () => {
85-
setOptimisticUserScore(downvoteResultScore);
86-
const action = isComment(props)
87-
? voteCommentAction.bind(
88-
null,
89-
props.commentId,
90-
downvoteResultScore,
91-
)
92-
: votePostAction.bind(null, props.postId, downvoteResultScore);
93-
await action();
94-
setUserScore(downvoteResultScore);
122+
await voteAction(downvoteResultScore);
95123
}}
96124
>
97125
<button type={"submit"}>

src/app/comment/Comment.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const Comment = (props: {
4747
const [deleted, setDeleted] = useState(props.commentView.comment.deleted);
4848
const [addedReplies, setAddedReplies] = useState<CommentNode[]>([]);
4949
const [saved, setSaved] = useState(props.commentView.saved);
50+
const [score, setScore] = useState(props.commentView.counts.score);
5051

5152
const markdownProps =
5253
editedContent !== null ? { content: editedContent } : props.markdown;
@@ -109,6 +110,7 @@ export const Comment = (props: {
109110
className={"peer-checked:collapse peer-checked:max-h-0"}
110111
commentId={props.commentView.comment.id}
111112
loggedInUserScore={props.commentView.my_vote}
113+
onScoreChange={setScore}
112114
postId={props.commentView.post.id}
113115
score={props.commentView.counts.score}
114116
voteConfig={props.voteConfig}
@@ -148,8 +150,7 @@ export const Comment = (props: {
148150
<div className={"flex flex-wrap items-center gap-1"}>
149151
{props.voteConfig.scoresVisible && (
150152
<div className={""}>
151-
{props.commentView.counts.score}{" "}
152-
{props.commentView.counts.score === 1 ? "point" : "points"}
153+
{score} {score === 1 ? "point" : "points"}
153154
</div>
154155
)}
155156
<FormattedTimestamp

0 commit comments

Comments
 (0)