From 3ead5199bd0279e1803eea1f4c3a208374588ad5 Mon Sep 17 00:00:00 2001 From: Brok3Turtl3 Date: Sat, 20 Apr 2024 12:32:21 -0400 Subject: [PATCH 1/2] CHE-64 Added a Post type and created basic ThreadDetail component --- .../Forums/ThreadDetails/ThreadDetails.tsx | 63 +++++++++++++++++++ client/types/forums.ts | 7 +++ 2 files changed, 70 insertions(+) create mode 100644 client/src/components/Forums/ThreadDetails/ThreadDetails.tsx diff --git a/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx b/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx new file mode 100644 index 0000000..04200db --- /dev/null +++ b/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx @@ -0,0 +1,63 @@ +import React, { useEffect, useState } from "react"; +import axios from "axios"; +import { Thread, IPost } from "../../../../types/forums"; + +interface ThreadDetailProps { + forumId: string; + threadId: string; +} + +const ThreadDetail: React.FC = ({ forumId, threadId }) => { + const [thread, setThread] = useState(null); + const [posts, setPosts] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchThreadDetails = async () => { + setLoading(true); + try { + const response = await axios.get( + `/api/forums/${forumId}/threads/${threadId}`, + { + withCredentials: true, + } + ); + setThread(response.data.thread); + setPosts(response.data.posts); + setLoading(false); + } catch (err) { + const error = err as Error; + setError(error.message); + setLoading(false); + } + }; + + fetchThreadDetails(); + }, [forumId, threadId]); + + if (loading) return
Loading...
; + if (error) return
Error: {error}
; + if (!thread) return
Thread not found.
; + + return ( +
+

{thread.title}

+

{thread.content}

+
+

Replies

+ {posts.map((post) => ( +
+

{post.content}

+ + By {post.user.firstName} {post.user.lastName} on{" "} + {new Date(post.createdAt).toLocaleDateString()} + +
+ ))} +
+
+ ); +}; + +export default ThreadDetail; diff --git a/client/types/forums.ts b/client/types/forums.ts index 32ff520..496cfea 100644 --- a/client/types/forums.ts +++ b/client/types/forums.ts @@ -18,3 +18,10 @@ export interface IForum { _id: string; title: string; } + +export interface IPost { + _id: string; + user: IUser; + content: string; + createdAt: string; +} From 1d49f9f1822a4488e928cd9f333ea7603bb716e8 Mon Sep 17 00:00:00 2001 From: Brok3Turtl3 Date: Sat, 20 Apr 2024 16:09:23 -0400 Subject: [PATCH 2/2] CHE-64 Functionality for displaying posts on threads in place --- .../Forums/ThreadDetails/ThreadDetails.tsx | 15 +++++++------- .../Forums/ThreadsDisplay/ThreadsDisplay.tsx | 12 +++++++++-- client/src/pages/Forums/Forums.tsx | 20 ++++++++++++++++++- server/controllers/threadController.ts | 4 ++-- server/routes/forumRoutes.ts | 1 + 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx b/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx index 04200db..253076d 100644 --- a/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx +++ b/client/src/components/Forums/ThreadDetails/ThreadDetails.tsx @@ -3,7 +3,7 @@ import axios from "axios"; import { Thread, IPost } from "../../../../types/forums"; interface ThreadDetailProps { - forumId: string; + forumId: string | null; threadId: string; } @@ -17,14 +17,13 @@ const ThreadDetail: React.FC = ({ forumId, threadId }) => { const fetchThreadDetails = async () => { setLoading(true); try { - const response = await axios.get( - `/api/forums/${forumId}/threads/${threadId}`, - { - withCredentials: true, - } - ); + const endpoint = forumId + ? `/api/forums/${forumId}/threads/${threadId}` + : `/api/forums/threads/${threadId}`; + const response = await axios.get(endpoint, { withCredentials: true }); setThread(response.data.thread); - setPosts(response.data.posts); + setPosts(response.data.posts || []); + setLoading(false); } catch (err) { const error = err as Error; diff --git a/client/src/components/Forums/ThreadsDisplay/ThreadsDisplay.tsx b/client/src/components/Forums/ThreadsDisplay/ThreadsDisplay.tsx index e539035..566474a 100644 --- a/client/src/components/Forums/ThreadsDisplay/ThreadsDisplay.tsx +++ b/client/src/components/Forums/ThreadsDisplay/ThreadsDisplay.tsx @@ -4,9 +4,13 @@ import { Thread, IForum } from "../../../../types/forums"; interface ThreadsDisplayProps { forumId?: string | null; + onThreadSelect: (threadId: string) => void; } -const ThreadsDisplay: React.FC = ({ forumId }) => { +const ThreadsDisplay: React.FC = ({ + forumId, + onThreadSelect, +}) => { const [threads, setThreads] = useState([]); const [forum, setForum] = useState(null); const [loading, setLoading] = useState(false); @@ -50,7 +54,11 @@ const ThreadsDisplay: React.FC = ({ forumId }) => {
    {threads.map((thread) => ( -
  • +
  • onThreadSelect(thread._id)} + >

    {thread.title}

    {thread.content}

    diff --git a/client/src/pages/Forums/Forums.tsx b/client/src/pages/Forums/Forums.tsx index 8d865c3..9d32b4f 100644 --- a/client/src/pages/Forums/Forums.tsx +++ b/client/src/pages/Forums/Forums.tsx @@ -1,13 +1,21 @@ import React, { useState } from "react"; import ForumsList from "../../components/Forums/ForumsList/ForumsList"; import ThreadsDisplay from "../../components/Forums/ThreadsDisplay/ThreadsDisplay"; +import ThreadDetails from "../../components/Forums/ThreadDetails/ThreadDetails"; const Forums = (): JSX.Element => { const [selectedForumId, setSelectedForumId] = useState(null); + const [selectedThreadId, setSelectedThreadId] = useState(null); const handleForumSelect = (forumId: string | null) => { setSelectedForumId(forumId); + setSelectedThreadId(null); }; + + const handleThreadSelect = (threadId: string) => { + setSelectedThreadId(threadId); + }; + return (
    @@ -18,7 +26,17 @@ const Forums = (): JSX.Element => {
    - + {selectedThreadId ? ( + + ) : ( + + )}
    ); diff --git a/server/controllers/threadController.ts b/server/controllers/threadController.ts index 854cb70..fd3009b 100644 --- a/server/controllers/threadController.ts +++ b/server/controllers/threadController.ts @@ -92,10 +92,10 @@ const getThreadById = async ( res: Response, next: NextFunction ) => { - const { forumId, threadId } = req.params; + const { threadId } = req.params; try { - const thread = await Thread.findOne({ _id: threadId, forum: forumId }) + const thread = await Thread.findOne({ _id: threadId }) .populate("user", "firstName lastName") .exec(); diff --git a/server/routes/forumRoutes.ts b/server/routes/forumRoutes.ts index f1a3e66..105ec55 100644 --- a/server/routes/forumRoutes.ts +++ b/server/routes/forumRoutes.ts @@ -28,6 +28,7 @@ import { protect } from "../middleware/authMiddleware"; //TODO Add admin auth mi const router = express.Router(); router.get("/threads", getAllThreads); +router.get("/threads/:threadId", protect, getThreadById); //Forum Routes router.post("/", protect, addForum); //TODO Protect with admin auth