diff --git a/app/api/blogs/fetchCommentsByBlogId.ts b/app/api/blogs/fetchCommentsByBlogId.ts new file mode 100644 index 0000000..1dcaf7e --- /dev/null +++ b/app/api/blogs/fetchCommentsByBlogId.ts @@ -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; +} diff --git a/app/api/blogs/getAllBlogs.ts b/app/api/blogs/getAllBlogs.ts index d88191f..0c699c6 100644 --- a/app/api/blogs/getAllBlogs.ts +++ b/app/api/blogs/getAllBlogs.ts @@ -6,5 +6,6 @@ import axios from 'axios'; export default async function getAllBlogs(): Promise { const url = `${config.backendUrl}blog/`; const res = await axios.get(url); + console.log(res.data.data.blogs); return res.data.data.blogs; } diff --git a/app/api/blogs/postComment.ts b/app/api/blogs/postComment.ts new file mode 100644 index 0000000..33a136e --- /dev/null +++ b/app/api/blogs/postComment.ts @@ -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; +} diff --git a/app/api/blogs/toggleLike.ts b/app/api/blogs/toggleLike.ts index f09a2bf..d5ff630 100644 --- a/app/api/blogs/toggleLike.ts +++ b/app/api/blogs/toggleLike.ts @@ -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; } diff --git a/app/blog/[id]/page.tsx b/app/blog/[id]/page.tsx index ead5cc0..4a91303 100644 --- a/app/blog/[id]/page.tsx +++ b/app/blog/[id]/page.tsx @@ -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'; @@ -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(); @@ -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 @@ -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 @@ -185,6 +207,27 @@ export default function BlogDetailPage() { }; }, []); + const handleComment = async (e: FormEvent) => { + 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; @@ -499,7 +542,7 @@ export default function BlogDetailPage() {