From ca4fb32413761fe1e751d63603ca74e8ab9fab42 Mon Sep 17 00:00:00 2001 From: Pau Costa Date: Sun, 11 Feb 2024 16:15:43 +0100 Subject: [PATCH] :sparkles: A Post and comments view Signed-off-by: Pau Costa --- client/src/app/postSlice.ts | 30 ++++++- client/src/components/appAvatar.tsx | 5 ++ client/src/index.tsx | 4 +- client/src/routes/post.tsx | 135 +++++++++++++++++++++++++++- 4 files changed, 169 insertions(+), 5 deletions(-) diff --git a/client/src/app/postSlice.ts b/client/src/app/postSlice.ts index 30ff9c4..c298498 100644 --- a/client/src/app/postSlice.ts +++ b/client/src/app/postSlice.ts @@ -7,12 +7,14 @@ interface postSliceInterface { status: Status; followedPosts: Post[]; globalPosts: Post[]; + aPost: Post | null; } const initialState: postSliceInterface = { status: Status.idle, followedPosts: [], globalPosts: [], + aPost: null, }; export const postSlice = createSlice({ @@ -28,6 +30,9 @@ export const postSlice = createSlice({ setGlobalPosts: (state, action) => { state.globalPosts = action.payload; }, + setAPost: (state, action) => { + state.aPost = action.payload; + }, }, }); @@ -69,7 +74,29 @@ export const unLikePost = dispatch(setStatus(Status.idle)); }; -export const { setFollowedPosts, setGlobalPosts, setStatus } = +export const fetchAPost = + (postId: number): AppThunk => + async (dispatch: any) => { + const postApi = createApi(store); + + dispatch(setStatus(Status.loading)); + const response = await postApi.getPost(postId); + dispatch(setAPost(response.data)); + dispatch(setStatus(Status.idle)); + }; + +export const commentAPost = + (postId: number, comment: string): AppThunk => + async (dispatch: any) => { + const postApi = createApi(store); + + dispatch(setStatus(Status.loading)); + await postApi.commentPost(postId, { content: comment }); + dispatch(fetchAPost(postId)); + dispatch(setStatus(Status.idle)); + }; + +export const { setFollowedPosts, setGlobalPosts, setStatus, setAPost } = postSlice.actions; export default postSlice.reducer; @@ -77,6 +104,7 @@ export default postSlice.reducer; export const selectFollowedPosts = (state: any) => state.post.followedPosts; export const selectAllPosts = (state: any) => state.post.globalPosts; export const selectStatus = (state: any) => state.post.status; +export const selectAPost = (state: any) => state.post.aPost; function createApi(store: Store) { return new PostsApi( diff --git a/client/src/components/appAvatar.tsx b/client/src/components/appAvatar.tsx index 43b2fd6..8a41df9 100644 --- a/client/src/components/appAvatar.tsx +++ b/client/src/components/appAvatar.tsx @@ -3,6 +3,7 @@ import { User, UserWithRelations } from "../api"; interface AppAvatarProps { user: User | UserWithRelations; + small?: boolean; } export function AppAvatar(props: AppAvatarProps) { @@ -10,6 +11,10 @@ export function AppAvatar(props: AppAvatarProps) { ); } diff --git a/client/src/index.tsx b/client/src/index.tsx index 4bd5348..d366174 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -14,7 +14,7 @@ import { Provider } from "react-redux"; import { store } from "./app/store"; import PostList from "./routes/postList"; import Profile from "./routes/profile"; -import Post from "./routes/post"; +import PostView from "./routes/post"; import NewPost from "./routes/newPost"; import Search from "./routes/search"; @@ -52,7 +52,7 @@ const router = createBrowserRouter([ }, { path: "post/:id", - element: , + element: , }, { path: "search", diff --git a/client/src/routes/post.tsx b/client/src/routes/post.tsx index b0a457c..06b636b 100644 --- a/client/src/routes/post.tsx +++ b/client/src/routes/post.tsx @@ -1,3 +1,134 @@ -export default function Post() { - return <>Post; +import { useSelector } from "react-redux"; +import { useParams } from "react-router-dom"; +import { commentAPost, fetchAPost, selectAPost } from "../app/postSlice"; +import { useAppDispatch } from "../app/store"; +import { useEffect } from "react"; +import React from "react"; +import { Post } from "../api"; +import { + Box, + Button, + Divider, + Paper, + TextField, + Typography, +} from "@mui/material"; +import { AppAvatar } from "../components/appAvatar"; + +export default function PostView() { + const postId = useParams<{ id: string }>().id; + const storePost = useSelector(selectAPost); + const [postToDisplay, setPostToDisplay] = React.useState(null); + const [newComentText, setNewCommentText] = React.useState(""); + const dispatch = useAppDispatch(); + + useEffect(() => { + dispatch(fetchAPost(parseInt(postId!, 10))); + }, []); + + useEffect(() => { + setPostToDisplay(storePost); + }, [storePost]); + + const handleCommentPost = () => { + if (newComentText.length > 0) { + dispatch(commentAPost(postToDisplay!.id!, newComentText)); + setNewCommentText(""); + } + }; + + const handleCancelComment = () => { + setNewCommentText(""); + }; + + return ( + + + + + + {postToDisplay?.createdBy && ( + + )} + + {postToDisplay?.createdBy?.firstName}{" "} + {postToDisplay?.createdBy?.lastName} + + + + {postToDisplay?.title} + {postToDisplay?.content} + + + + + setNewCommentText(e.target.value)} + InputProps={{ + endAdornment: ( + <> + + + + ), + }} + sx={{ + mb: "1rem", + }} + /> + + {postToDisplay?.comments?.map((comment) => ( + + + + + + {comment.createdBy?.firstName} {comment.createdBy?.lastName} + + + + {comment.content} + + + ))} + + + + ); }