diff --git a/Frontend/src/api/api.js b/Frontend/src/api/api.js
index 28d631a..05ea5d8 100644
--- a/Frontend/src/api/api.js
+++ b/Frontend/src/api/api.js
@@ -141,15 +141,21 @@ export const createDiscussion = (payload) => {
}
export const likeDiscussion = (discussionId) => {
- return axios.get(`${BASE}/${discussionId}/like`, { withCredentials: true });
+ return axios.post(`${BASE}/discussion/${discussionId}/like`, {}, {
+ withCredentials: true,
+ headers: { Authorization: `Bearer ${accessToken}` }
+ });
}
export const dislikeDiscussion = (discussionId) => {
- return axios.get(`${BASE}/${discussionId}/dislike`, { withCredentials: true });
+ return axios.post(`${BASE}/discussion/${discussionId}/dislike`, {}, {
+ withCredentials: true,
+ headers: { Authorization: `Bearer ${accessToken}` }
+ });
}
export const createComment = (discussionId, comment) => {
- return axios.post(`${BASE}/${discussionId}/comment`, comment, {
+ return axios.post(`${BASE}/discussion/${discussionId}/comment`, comment, {
withCredentials: true,
headers: { Authorization: `Bearer ${accessToken}` }
})
diff --git a/Frontend/src/components/NavBar.jsx b/Frontend/src/components/NavBar.jsx
index 5606716..b164b4e 100644
--- a/Frontend/src/components/NavBar.jsx
+++ b/Frontend/src/components/NavBar.jsx
@@ -54,6 +54,7 @@ export default function NewNav() {
const navItems = [
{ to: "/", label: "Home" },
{ to: "/problems", label: "Problems" },
+ { to: "/discussion", label: "Discussions" },
...(userRole === "author" || userRole === "admin"
? [{ to: "/newproblem", label: "Create Problem" }]
: []),
diff --git a/Frontend/src/pages/DiscussionPage.jsx b/Frontend/src/pages/DiscussionPage.jsx
index cd11097..3aaed9b 100644
--- a/Frontend/src/pages/DiscussionPage.jsx
+++ b/Frontend/src/pages/DiscussionPage.jsx
@@ -1,82 +1,301 @@
-import React, { useEffect , useState } from 'react';
-import {getAllDiscussion} from '@/api/api';
+import React, { useEffect, useState } from 'react';
+import { getAllDiscussion, createDiscussion, likeDiscussion, dislikeDiscussion, createComment } from '@/api/api';
+import { useAuth } from '@/auth/AuthContext';
const DiscussionPage = () => {
- const [discussion,setDiscussion] = useState([{
- _id : 1,content : "your name is shivam",like : 1,dislike : 3
- }]);
- const [formData,setFormData] = useState({
- title : "",
- description : "",
- tags : ""
- })
-
- const Field = ({ label, hint, children }) => (
-
-
-
- {hint && {hint}}
-
- {children}
-
- );
+ const { user } = useAuth();
+ const [discussions, setDiscussions] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState('');
+ const [showCreateForm, setShowCreateForm] = useState(false);
+ const [formData, setFormData] = useState({
+ title: '',
+ content: '',
+ tags: ''
+ });
+ const [commentData, setCommentData] = useState({});
+ const [showComments, setShowComments] = useState({});
+
+ useEffect(() => {
+ fetchDiscussions();
+ }, []);
+
+ const fetchDiscussions = async () => {
+ try {
+ setLoading(true);
+ setError('');
+ const response = await getAllDiscussion();
+ setDiscussions(Array.isArray(response.data.data) ? response.data.data : []);
+ } catch (err) {
+ setError('Failed to load discussions. Please try again.');
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleCreateDiscussion = async (e) => {
+ e.preventDefault();
+ if (!user) {
+ setError('Please login to create a discussion');
+ return;
+ }
- // useEffect(()=> {
- // async function fetchDiscussion(){
- // try{
- // const response = await getAllDiscussion();
- // setDiscussion(response.data.message);
- // }catch(error){
- // console.error(error);
- // }
- // }
- // fetchDiscussion();
- // },[])
+ try {
+ const payload = {
+ title: formData.title,
+ content: formData.content,
+ tags: formData.tags ? formData.tags.split(',').map(tag => tag.trim()) : []
+ };
+
+ await createDiscussion(payload);
+ setFormData({ title: '', content: '', tags: '' });
+ setShowCreateForm(false);
+ fetchDiscussions();
+ } catch (err) {
+ setError('Failed to create discussion. Please try again.');
+ console.error(err);
+ }
+ };
- const handleDiscussionCreation = () => {
+ const handleLike = async (discussionId) => {
+ if (!user) {
+ setError('Please login to like discussions');
+ return;
+ }
+ try {
+ await likeDiscussion(discussionId);
+ fetchDiscussions();
+ } catch (err) {
+ console.error('Failed to like discussion:', err);
+ }
+ };
- }
+ const handleDislike = async (discussionId) => {
+ if (!user) {
+ setError('Please login to dislike discussions');
+ return;
+ }
+ try {
+ await dislikeDiscussion(discussionId);
+ fetchDiscussions();
+ } catch (err) {
+ console.error('Failed to dislike discussion:', err);
+ }
+ };
+
+ const handleAddComment = async (discussionId) => {
+ if (!user) {
+ setError('Please login to comment');
+ return;
+ }
+ const content = commentData[discussionId];
+ if (!content || !content.trim()) return;
+
+ try {
+ await createComment(discussionId, { content });
+ setCommentData({ ...commentData, [discussionId]: '' });
+ fetchDiscussions();
+ } catch (err) {
+ console.error('Failed to add comment:', err);
+ }
+ };
+
+ const toggleComments = (discussionId) => {
+ setShowComments(prev => ({ ...prev, [discussionId]: !prev[discussionId] }));
+ };
return (
- <>
-
-
-
-
-
- {discussion.map(dis=>(
-
-
{dis.content}
-
{dis.like}
-
{dis.dislike}
+
+
+
+
+
Discussions
+
Share ideas, ask questions, and engage with the community
+
+ {user && (
+
+ )}
+
+
+ {error && (
+
+ {error}
- ))}
+ )}
+
+ {showCreateForm && (
+
+
Create New Discussion
+
+
+ )}
+
+ {loading ? (
+
+ {Array.from({ length: 3 }).map((_, i) => (
+
+ ))}
+
+ ) : discussions.length === 0 ? (
+
+
+
No discussions yet
+
Be the first to start a discussion!
+
+ ) : (
+
+ {discussions.map((discussion) => (
+
+
+
{discussion.title}
+
{discussion.content}
+
+
+ {discussion.tags && discussion.tags.length > 0 && (
+
+ {discussion.tags.map((tag, idx) => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+ {showComments[discussion._id] && (
+
+ {discussion.comments && discussion.comments.length > 0 && (
+
+ {discussion.comments.map((comment, idx) => (
+
+ ))}
+
+ )}
+ {user && (
+
+ setCommentData({ ...commentData, [discussion._id]: e.target.value })}
+ placeholder="Add a comment..."
+ className="flex-1 rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-sm text-white placeholder:text-slate-400 focus:border-indigo-400 focus:outline-none"
+ />
+
+
+ )}
+
+ )}
+
+ ))}
+
+ )}
- >
- )
-}
+
+ );
+};
export default DiscussionPage;
\ No newline at end of file
diff --git a/backend/src/controllers/discussion.controller.js b/backend/src/controllers/discussion.controller.js
index 78433c0..def0e90 100644
--- a/backend/src/controllers/discussion.controller.js
+++ b/backend/src/controllers/discussion.controller.js
@@ -38,7 +38,7 @@ export const createDiscussion = asyncHandler (async (req,res)=>{
export const getDiscussions = asyncHandler(async (req,res)=> {
const cachedDiscussions = await redis.get('allDiscussions');
if (cachedDiscussions) {
- return res.status(200).json(new ApiResponse(200, JSON.parse(cachedDiscussions), "Discussions fetched successfully from cache"));
+ return res.status(200).json(new ApiResponse(200, "Discussions fetched successfully from cache", JSON.parse(cachedDiscussions)));
}
const discussions = await Discussion.find()
@@ -53,8 +53,8 @@ export const getDiscussions = asyncHandler(async (req,res)=> {
export const createComment = asyncHandler(async (req,res)=> {
- const content = req.body;
- const discussionId = req.params;
+ const { content } = req.body;
+ const { discussionId } = req.params;
if (!discussionId || !content) {
throw new ApiError(400, "Discussion ID and content are required");
diff --git a/backend/src/routes/discussion.route.js b/backend/src/routes/discussion.route.js
index 97ed62f..8713a17 100644
--- a/backend/src/routes/discussion.route.js
+++ b/backend/src/routes/discussion.route.js
@@ -1,14 +1,15 @@
import {Router} from 'express';
import {createDiscussion,getDiscussions,likeDiscussion,createComment,dislikeDiscussion,deleteDiscussion} from '../controllers/discussion.controller.js';
import { verifyJWT } from '../middlewares/auth.middleware.js';
+import { rateLimitMiddleware } from '../middlewares/ratelimiter.middleware.js';
const router = Router();
router.get('/',getDiscussions);
-router.post('/',verifyJWT,createDiscussion);
-router.delete('/',verifyJWT,deleteDiscussion);
-router.post('/:discussionId/comment',verifyJWT,createComment);
-router.get('/:disscussionId/like',verifyJWT,likeDiscussion);
-router.get('/:discussionId/dislike',verifyJWT,dislikeDiscussion);
+router.post('/',verifyJWT,rateLimitMiddleware,createDiscussion);
+router.delete('/:discussionId',verifyJWT,deleteDiscussion);
+router.post('/:discussionId/comment',verifyJWT,rateLimitMiddleware,createComment);
+router.post('/:discussionId/like',verifyJWT,rateLimitMiddleware,likeDiscussion);
+router.post('/:discussionId/dislike',verifyJWT,rateLimitMiddleware,dislikeDiscussion);
export default router;
\ No newline at end of file