diff --git a/client/src/actions/posts.jsx b/client/src/actions/posts.jsx index ba1e40f..bc8e384 100644 --- a/client/src/actions/posts.jsx +++ b/client/src/actions/posts.jsx @@ -1,5 +1,5 @@ import * as api from '../api'; -import { CREATE, UPDATE, DELETE, FETCH_ALL, FETCH_POST, FETCH_BY_SEARCH, START_LOADING, END_LOADING } from '../constants/actionTypes'; +import { CREATE, UPDATE, DELETE, FETCH_ALL, FETCH_POST, FETCH_BY_SEARCH, START_LOADING, END_LOADING, COMMENT } from '../constants/actionTypes'; //Action Creators export const getPosts = (page) => async (dispatch) => { @@ -82,4 +82,16 @@ export const likePost = (id) => async (dispatch) => { } catch (error) { console.log(error); } -} \ No newline at end of file +} + +export const commentPost = (value, id) => async (dispatch) => { + try { + const { data } = await api.comment(value, id); + + dispatch({ type: COMMENT, payload: data }); + + return data.comments; + } catch (error) { + console.log(error); + } + }; \ No newline at end of file diff --git a/client/src/api/index.jsx b/client/src/api/index.jsx index d38e6ea..ac73c20 100644 --- a/client/src/api/index.jsx +++ b/client/src/api/index.jsx @@ -17,6 +17,7 @@ export const createPost = (newPost) => API.post('/posts', newPost); export const updatePost = (id, updatedPost) => API.patch(`/posts/${id}`, updatedPost); export const deletePost = (id) => API.delete(`/posts/${id}`); export const likePost = (id) => API.patch(`/posts/${id}/likePost`); +export const comment = (value, id) => API.post(`/posts/${id}/commentPost`, { value }); export const signIn = (formData) => API.post('/user/signin', formData); export const signUp = (formData) => API.post('/user/signup', formData); \ No newline at end of file diff --git a/client/src/components/PostDetails/CommentSection.jsx b/client/src/components/PostDetails/CommentSection.jsx new file mode 100644 index 0000000..0e40268 --- /dev/null +++ b/client/src/components/PostDetails/CommentSection.jsx @@ -0,0 +1,53 @@ +import React, { useState, useRef } from 'react'; +import { Typography, TextField, Button } from '@material-ui/core/'; +import { useDispatch } from 'react-redux'; + +import { commentPost } from '../../actions/posts'; +import useStyles from './styles'; + +const CommentSection = ({ post }) => { + const user = JSON.parse(localStorage.getItem('profile')); + const [comment, setComment] = useState(''); + const dispatch = useDispatch(); + const [comments, setComments] = useState(post?.comments); + const classes = useStyles(); + const commentsRef = useRef(); + + const handleComment = async () => { + const newComments = await dispatch(commentPost(`${user?.result?.name}: ${comment}`, post._id)); + + setComment(''); + setComments(newComments); + + commentsRef.current.scrollIntoView({ behavior: 'smooth' }); + }; + + return ( +
+
+
+ Comments + {comments?.map((c, i) => ( + + {c.split(': ')[0]} + {c.split(':')[1]} + + ))} +
+
+ {user?.result?.name && ( +
+ Write a comment + setComment(e.target.value)} /> +
+ +
+ )} +
+
+ ); +}; + +export default CommentSection; \ No newline at end of file diff --git a/client/src/components/PostDetails/PostDetails.jsx b/client/src/components/PostDetails/PostDetails.jsx index d6135d3..564438e 100644 --- a/client/src/components/PostDetails/PostDetails.jsx +++ b/client/src/components/PostDetails/PostDetails.jsx @@ -3,6 +3,7 @@ import { Paper, Typography, CircularProgress, Divider} from '@material-ui/core'; import { useDispatch, useSelector } from 'react-redux'; import moment from 'moment'; import { useParams, useHistory } from 'react-router'; +import CommentSection from './CommentSection'; import useStyles from './styles'; @@ -53,7 +54,7 @@ const PostDetails = () => { Realtime Chat - coming soon! - Comments - coming soon! +
diff --git a/client/src/components/PostDetails/styles.jsx b/client/src/components/PostDetails/styles.jsx index 8b1c281..2a72e27 100644 --- a/client/src/components/PostDetails/styles.jsx +++ b/client/src/components/PostDetails/styles.jsx @@ -42,4 +42,13 @@ export default makeStyles((theme) => ({ loadingPaper: { display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '20px', borderRadius: '15px', height: '39vh', }, + commentsOuterContainer: { + display: 'flex', + justifyContent: 'space-between', + }, + commentsInnerContainer: { + height: '200px', + overflowY: 'auto', + marginRight: '30px', + }, })); \ No newline at end of file diff --git a/client/src/constants/actionTypes.jsx b/client/src/constants/actionTypes.jsx index 4cafcb2..779268c 100644 --- a/client/src/constants/actionTypes.jsx +++ b/client/src/constants/actionTypes.jsx @@ -4,6 +4,7 @@ export const DELETE = 'DELETE'; export const FETCH_ALL = 'FETCH_ALL'; export const FETCH_POST = 'FETCH_POST'; export const FETCH_BY_SEARCH = 'FETCH_BY_SEARCH'; +export const COMMENT = 'COMMENT'; export const START_LOADING = 'START_LOADING'; export const END_LOADING = 'END_LOADING'; diff --git a/client/src/reducers/posts.jsx b/client/src/reducers/posts.jsx index 5afaf01..60b0d94 100644 --- a/client/src/reducers/posts.jsx +++ b/client/src/reducers/posts.jsx @@ -1,4 +1,4 @@ -import { CREATE, UPDATE, DELETE, FETCH_ALL, FETCH_POST, FETCH_BY_SEARCH, START_LOADING, END_LOADING } from '../constants/actionTypes'; +import { CREATE, UPDATE, DELETE, FETCH_ALL, FETCH_POST, FETCH_BY_SEARCH, COMMENT, START_LOADING, END_LOADING } from '../constants/actionTypes'; const posts = (state = { isLoading: true, posts: [] }, action) => { switch (action.type) { @@ -32,7 +32,18 @@ const posts = (state = { isLoading: true, posts: [] }, action) => { case DELETE: return { ...state, posts: state.posts.filter((post) => post._id !== action.payload) }; - + + case COMMENT: + return { + ...state, + posts: state.posts.map((post) => { + if (post._id === action.payload._id) { + return action.payload; + } + return post; + }), + }; + default: return state; } diff --git a/server/controllers/posts.js b/server/controllers/posts.js index a539b3e..8d7b88b 100644 --- a/server/controllers/posts.js +++ b/server/controllers/posts.js @@ -106,4 +106,17 @@ export const likePost = async (req, res) => { const updatedPost = await PostMessage.findByIdAndUpdate(id, post, { new: true }); res.json(updatedPost); -} \ No newline at end of file +} + +export const commentPost = async (req, res) => { + const { id } = req.params; + const { value } = req.body; + + const post = await PostMessage.findById(id); + + post.comments.push(value); + + const updatedPost = await PostMessage.findByIdAndUpdate(id, post, { new: true }); + + res.json(updatedPost); +}; \ No newline at end of file diff --git a/server/models/postMessage.js b/server/models/postMessage.js index a93fe3c..d8efdf4 100644 --- a/server/models/postMessage.js +++ b/server/models/postMessage.js @@ -11,6 +11,10 @@ const postSchema = mongoose.Schema({ type: [String], default: [], }, + comments: { + type: [String], + default: [] + }, createdAt: { type: Date, default: new Date(), diff --git a/server/routes/posts.js b/server/routes/posts.js index fcb8f08..197ca5e 100644 --- a/server/routes/posts.js +++ b/server/routes/posts.js @@ -1,6 +1,6 @@ import express from 'express'; -import { getPost, getPosts, getPostsBySearch, createPost, updatePost, deletePost, likePost } from '../controllers/posts.js'; +import { getPost, getPosts, getPostsBySearch, createPost, updatePost, deletePost, likePost, commentPost } from '../controllers/posts.js'; import auth from '../middleware/auth.js'; @@ -13,5 +13,6 @@ router.post('/', auth, createPost); router.patch('/:id', auth, updatePost); router.delete('/:id', auth, deletePost); router.patch('/:id/likePost', auth, likePost); +router.post('/:id/commentPost', commentPost); export default router; \ No newline at end of file