Skip to content

Commit b672c4f

Browse files
authored
Merge pull request #352 from yashpandav/reaction-frontend
Frontend Implementation for User Reactions
2 parents 2ec7859 + b4c5e53 commit b672c4f

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

front-end/src/pages/Article.jsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,111 @@ import { useSelector } from 'react-redux';
1616
import SaveForLaterButton from '../components/SaveForLaterComp/SaveforlaterButton';
1717
Modal.setAppElement('#root');
1818

19+
const ReactionButton = ({ articleId, usertoken }) => {
20+
const [reactionCounts, setReactionCounts] = useState({});
21+
const [userReaction, setUserReaction] = useState(null);
22+
const [loading, setLoading] = useState(false);
23+
const [showReactions, setShowReactions] = useState(false);
24+
const validEmojis = ['👍', '❤️', '😂', '😮', '😢', '😡'];
25+
26+
useEffect(() => {
27+
const fetchReactions = async () => {
28+
try {
29+
const response = await axios.get(`${link}/api/article/reactions/${articleId}`);
30+
setReactionCounts(response.data.reactionCounts || {});
31+
const userReaction = response.data.reactions.find(r => r.user?._id === JSON.parse(atob(usertoken.split('.')[1])).userId)?.emoji;
32+
setUserReaction(userReaction);
33+
} catch (error) {
34+
console.error('Error fetching reactions:', error);
35+
}
36+
};
37+
fetchReactions();
38+
}, [articleId, usertoken]);
39+
40+
const handleReaction = async (emoji) => {
41+
if (!usertoken) {
42+
alert('Please login to react');
43+
return;
44+
}
45+
46+
try {
47+
setLoading(true);
48+
if (userReaction === emoji) {
49+
await axios.delete(`${link}/api/article/react/${articleId}`, {
50+
headers: { Authorization: `Bearer ${usertoken}` }
51+
});
52+
setUserReaction(null);
53+
setReactionCounts(prev => ({ ...prev, [emoji]: (prev[emoji] || 1) - 1 }));
54+
} else {
55+
await axios.post(`${link}/api/article/react/${articleId}`, { emoji }, {
56+
headers: { Authorization: `Bearer ${usertoken}` }
57+
});
58+
if (userReaction) {
59+
setReactionCounts(prev => ({
60+
...prev,
61+
[userReaction]: (prev[userReaction] || 1) - 1,
62+
[emoji]: (prev[emoji] || 0) + 1
63+
}));
64+
} else {
65+
setReactionCounts(prev => ({ ...prev, [emoji]: (prev[emoji] || 0) + 1 }));
66+
}
67+
setUserReaction(emoji);
68+
}
69+
} catch (error) {
70+
console.error('Error updating reaction:', error);
71+
alert(error.response?.data?.error || 'Failed to update reaction');
72+
} finally {
73+
setLoading(false);
74+
}
75+
};
76+
77+
return (
78+
<div className="relative inline-block">
79+
{/* Main reaction button that shows current reaction or default */}
80+
<button
81+
onMouseEnter={() => setShowReactions(true)}
82+
className={`p-2 rounded-lg transition-all duration-200
83+
${userReaction ? 'bg-blue-100 dark:bg-yellow-900' : 'bg-gray-100 dark:bg-gray-700'}
84+
`}
85+
>
86+
<span className="text-xl">{userReaction || '👍'}</span>
87+
<span className="ml-2 text-sm font-medium">
88+
{reactionCounts[userReaction] || reactionCounts['👍'] || 0}
89+
</span>
90+
</button>
91+
92+
{/* Reaction picker popup */}
93+
{showReactions && (
94+
<div
95+
className="absolute bottom-full left-0 mb-2 bg-white dark:bg-gray-800 rounded-lg shadow-lg p-2 flex gap-1"
96+
onMouseEnter={() => setShowReactions(true)}
97+
onMouseLeave={() => setShowReactions(false)}
98+
>
99+
{validEmojis.map(emoji => (
100+
<button
101+
key={emoji}
102+
onClick={() => {
103+
handleReaction(emoji);
104+
setShowReactions(false);
105+
}}
106+
disabled={loading}
107+
className={`p-2 rounded-lg transition-all duration-200 hover:scale-125
108+
${userReaction === emoji
109+
? 'bg-blue-100 dark:bg-yellow-900'
110+
: 'hover:bg-gray-100 dark:hover:bg-gray-700'
111+
}
112+
`}
113+
title={userReaction === emoji ? 'Remove reaction' : 'Add reaction'}
114+
>
115+
<span className="text-xl">{emoji}</span>
116+
</button>
117+
))}
118+
</div>
119+
)}
120+
</div>
121+
);
122+
};
123+
19124
const Article = ({ loggedInUserId }) => {
20125
const { name } = useParams();
21126
const [article, setArticle] = useState(null);
@@ -219,6 +324,10 @@ const Article = ({ loggedInUserId }) => {
219324
initialLikes={article.likes || 0}
220325
initialLikedState={likedBy?.includes(userId)}
221326
/>
327+
<ReactionButton
328+
articleId={article._id}
329+
usertoken={localStorage.getItem('token')}
330+
/>
222331
<button
223332
onClick={() => {
224333
if (!localStorage.getItem('token')) {

0 commit comments

Comments
 (0)