@@ -16,6 +16,111 @@ import { useSelector } from 'react-redux';
1616import SaveForLaterButton from '../components/SaveForLaterComp/SaveforlaterButton' ;
1717Modal . 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+
19124const 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