Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/api/blogs/fetchCommentsByBlogId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import config from '@/lib/config';
import axios from 'axios';

export default async function fetchCommentsByBlogId(id: string) {
const res = await axios.get(`${config.backendUrl}blog/comment/${id}`);
console.log(res.data);
return res.data.comments;
}
1 change: 1 addition & 0 deletions app/api/blogs/getAllBlogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import axios from 'axios';
export default async function getAllBlogs(): Promise<BlogPost[]> {
const url = `${config.backendUrl}blog/`;
const res = await axios.get(url);
console.log(res.data.data.blogs);
return res.data.data.blogs;
}
21 changes: 21 additions & 0 deletions app/api/blogs/postComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import config from '@/lib/config';
import axios from 'axios';

export default async function postComment(
sessionId: string,
blogId: string,
comment: string
) {
const res = await axios.post(
`${config.backendUrl}blog/comment/${blogId}`,
{
comment,
},
{
headers: {
Authorization: `Bearer ${sessionId}`,
},
}
);
return res.data.comment;
}
5 changes: 4 additions & 1 deletion app/api/blogs/toggleLike.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ export default async function toggleLike(token: string, id: string) {
},
}
);
return res.data.blog;

console.log(res.data);

return res.data.liked;
}
91 changes: 61 additions & 30 deletions app/blog/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useState, useEffect, useRef, useMemo } from 'react';
import { useState, useEffect, useRef, useMemo, FormEvent } from 'react';
import { useParams, useRouter } from 'next/navigation';
import Image from 'next/image';
import Link from 'next/link';
Expand All @@ -25,9 +25,14 @@ import { BlogPost } from '@/types/blog';
// import postsData from '@/data/post.json';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '@/app/store/store';
import getBlogById from '@/app/api/blogs/getBlogById';
import toggleLike from '@/app/api/blogs/toggleLike';
import useAuth from '@/hooks/auth/useAuth';
import { refreshBlog } from '@/app/store/features/blogs/blogsSlice';
import postComment from '@/app/api/blogs/postComment';
import fetchCommentsByBlogId from '@/app/api/blogs/fetchCommentsByBlogId';

export default function BlogDetailPage() {
const params = useParams();
Expand All @@ -49,9 +54,13 @@ export default function BlogDetailPage() {
const [showTextShareMenu, setShowTextShareMenu] = useState(false);
const [showComments, setShowComments] = useState(false);
const [comments, setComments] = useState<
{ user: string; text: string; date: string }[]
// eslint-disable-next-line @typescript-eslint/no-explicit-any
{ userId: string; comment: string; updatedAt: string; user: any }[]
>([]);
const [newComment, setNewComment] = useState('');
const { getToken } = useAuth();
const dispatch = useDispatch();
const user = useSelector((state: RootState) => state.user);

// Get all blogs from Redux store
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down Expand Up @@ -128,16 +137,29 @@ export default function BlogDetailPage() {
return filtered;
}, [post, allBlogs]);

const fetchData = async (id: string) => {
const foundPost = (await getBlogById(id)) as BlogPost;
const foundComments = await fetchCommentsByBlogId(id);
if (foundPost) {
console.log('likes:');
console.log(foundPost.likes);
setPost(foundPost);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (
foundPost.likes.filter((likes: any) => likes.userId !== user.user?.id)
.length > 0
)
setIsLiked(true);
setComments(foundComments || []);
dispatch(refreshBlog(foundPost));
const wordCount = foundPost.excerpt.split(' ').length * 10; // Simulated content length
setReadingTime(Math.ceil(wordCount / 200));
}
};

useEffect(() => {
const fetchData = async () => {
const foundPost = await getBlogById(params.id?.toString() || '');
if (foundPost) {
setPost(foundPost);
const wordCount = foundPost.excerpt.split(' ').length * 10; // Simulated content length
setReadingTime(Math.ceil(wordCount / 200));
}
};
fetchData();
fetchData(params.id?.toString() || '');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params.id]);

// Handle text selection in the article
Expand Down Expand Up @@ -185,6 +207,27 @@ export default function BlogDetailPage() {
};
}, []);

const handleComment = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!newComment.trim()) return;
await postComment(
(await getToken())!,
params.id?.toString() || '',
newComment
);
await fetchData(params.id?.toString() || '');
setNewComment('');
};

const handleLike = async () => {
const liked = await toggleLike(
(await getToken())!,
params.id?.toString() || ''
);
await fetchData(params.id?.toString() || '');
setIsLiked(liked);
};

const handleTextShare = (platform: string) => {
if (!selectedText) return;
const url = window.location.href;
Expand Down Expand Up @@ -499,15 +542,15 @@ export default function BlogDetailPage() {
<div className="flex items-center justify-between">
<div className="flex items-center space-x-6">
<button
onClick={() => setIsLiked(!isLiked)}
onClick={handleLike}
className={`flex items-center space-x-2 px-4 py-2 rounded-full transition-all duration-200 ${
isLiked
? 'bg-red-100 text-red-600'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
<Heart className={`w-5 h-5 ${isLiked ? 'fill-current' : ''}`} />
<span className="font-medium">{isLiked ? '124' : '123'}</span>
<span className="font-medium">{post.likes.length}</span>
</button>

<button
Expand Down Expand Up @@ -535,19 +578,7 @@ export default function BlogDetailPage() {
<div className="mt-8 p-6 bg-gray-50 rounded-xl shadow-inner">
<h4 className="text-lg font-semibold mb-4">Comments</h4>
<form
onSubmit={e => {
e.preventDefault();
if (!newComment.trim()) return;
setComments([
...comments,
{
user: 'Anonymous', // Replace with actual user if available
text: newComment,
date: new Date().toISOString(),
},
]);
setNewComment('');
}}
onSubmit={handleComment}
className="flex flex-col gap-2 mb-6"
>
<textarea
Expand Down Expand Up @@ -576,11 +607,11 @@ export default function BlogDetailPage() {
className="bg-white p-4 rounded-lg shadow flex flex-col"
>
<span className="font-medium text-gray-800">
{comment.user}
{comment.user.name}
</span>
<span className="text-gray-600">{comment.text}</span>
<span className="text-gray-600">{comment.comment}</span>
<span className="text-xs text-gray-400 mt-1">
{new Date(comment.date).toLocaleString()}
{new Date(comment.updatedAt).toLocaleString()}
</span>
</div>
))}
Expand Down
10 changes: 10 additions & 0 deletions app/store/features/blogs/blogsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ const blogsSlice = createSlice({
console.log('Setting user blogs:', action.payload);
state.userBlogs = action.payload;
},
refreshBlog(state, action: PayloadAction<BlogPost>) {
state.blogs =
state.blogs?.filter(post => post.id !== action.payload.id) || [];
state.blogs.push(action.payload);

state.userBlogs =
state.userBlogs?.filter(post => post.id !== action.payload.id) || [];
state.userBlogs.push(action.payload);
},
clearBlogs(state) {
state.blogs = null;
},
Expand All @@ -47,6 +56,7 @@ export const {
clearBlogs,
clearUserBlogs,
deleteBlog,
refreshBlog,
deleteUserBlog,
} = blogsSlice.actions;
export default blogsSlice.reducer;
Loading