-
Social Media 만들기 - 13) update post , delete post, clipboard에 주소 복사 구현하기(Card Header)NODE.JS 2021. 7. 12. 02:09
이젠 포스트를 보여주는 헤더에서 edit post를 실행시켜보자.
먼저 edit 버튼을 누르면 status modal 이 뜨도록 설정해서 편집을 진행하자.
먼저 editstatus를 만들자.
export const EDITSTATUS = 'EDITSTATUS'
export const editstatusReducer = (state={}, action)=>{ switch(action.type){ case EDITSTATUS: return action.payload default: return state } }
function CardHeader({post}) { const handleEditPost = () =>{ dispatch({ type:STATUS, payload:true }) dispatch({ type:EDITSTATUS, payload:{ ...post, onEdit:true, } }) } <div className="dropdown-menu"> { userInfo.user._id ===post.user._id && <> <div className="dropdown-item"> <span className="material-icons" onClick={handleEditPost}>create</span> Edit Post </div> <div className="dropdown-item"> <span className="material-icons">delete_outline</span> Remove Post </div> </>
update라우터를 먼저 만들어주자.
postRouter.patch('/:id', auth, async(req, res)=>{ // console.log(req.body) try{ const updatedPost = await Post.findOneAndUpdate({_id:req.params.id},{'content':req.body.content, 'images':req.body.images}) .populate("user likes", "avatar username fullname") // .populate({ // path:"comments", // populate:{ // path:"user likes", // select:"-password" // } // }) console.log(updatedPost) res.send({updatedPost}) }catch(err){ return res.status(500).json({message:err.message}) } })
postupdateActions
이미 bodyFormdata가 설정되어 있지 않은 파일들은 설정해주고,
이미 설정되어있는(기존의 파일들은)파일들은 그대로 사용해주도록 한다.
export const updatePost = ({content, Images, editstatus}) =>async(dispatch, getState)=>{ const {userLogin:{userInfo}} = getState() dispatch({ type:UPDATE_POST_REQUEST, payload:{loading:true} }) try{ let imgArr = []; const imgNewUrl = Images.filter(img=>!img.data) const imgOldUrl = Images.filter(img=>img.data) if(imgNewUrl.length>0){ for(const item of imgNewUrl){ const bodyFormData = new FormData() if(item.camera){ bodyFormData.append("image", item.camera) }else{ bodyFormData.append("image", item) } const data = await axios.post('/api/postuploads', bodyFormData,{ headers:{'Content-Type' : 'multipart/form-data', authorization:`Bearer ${userInfo.token}`} }) imgArr.push(data) } } const res = await axios.patch(`/api/post/${editstatus._id}`, {content, images:[...imgOldUrl,...imgArr]},{ headers:{authorization:`Bearer ${userInfo.token}`} }) console.log(res) dispatch({ type:UPDATE_POST_SUCCESS, payload:res.data.updatedPost }) }catch(error){ dispatch({ type:UPDATE_POST_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message }) } }
post reducer
export const postUpdateReducer = (state={}, action)=>{ switch(action.type){ case UPDATE_POST_REQUEST: return {loading:true, success:false} case UPDATE_POST_SUCCESS: return {loading:false, updatedpost:action.payload, success:true} case UPDATE_POST_FAIL: return {loading:false, error:action.payload, success:false} case UPDATE_POST_RESET: return {} default: return state } }
store.js
updatepost:postUpdateReducer,
이제 statemodal에서 만약 edit 이 true라면,
포스트내용을 컨텐트, image로 set해준다.
submit할때,onedit이 트루라면 update를,
아니라면 create를 dispatch하도록 한다.
이미지는 이미 url이 설정 되어있다면, 따로 creatURL하지 않도록 설정해준다.
파일 업데이트 생성 완료하면 status, editstatus는 비워준다.
const handleSubmit= (e) =>{ e.preventDefault() if(Images.length===0){ return dispatch({type:ALERT, payload:{error:"Please add your photo."}}) } if(editstatus.onEdit){ dispatch(updatePost({content, Images, editstatus})) }else{ dispatch(createPost({content, Images})) } setcontent('') setImages([]) if(tracks) tracks.stop() dispatch({type:STATUS, payload:false}) dispatch({type:EDITSTATUS, payload:{}}) } useEffect(() => { if(editstatus.onEdit){ setcontent(editstatus.content) setImages(editstatus.images) } }, [editstatus]) <div className="show_images"> { Images && Images.map((image, index)=>( <div key={index} id="file_img"> <img src={image.camera ? image.camera : image.data ? image.data : URL.createObjectURL(image)} alt="images" className="img-thumbnail rounded" style={{filter:theme? 'invert(1)':'inver(0)'}} /> <span onClick={()=>deleteImage(index)}>×</span> </div> )) } </div>
post.js
useEffect(() => { if(success||updatesuccess){ dispatch({type:GET_POSTS_RESET}) dispatch({type:CREATE_POST_RESET}) dispatch({type:UPDATE_POST_RESET}) } dispatch(getHomePosts()) }, [dispatch, success, updatesuccess])
이제 delete를 구현하자.
postRouter.js
postRouter.delete('/:id', auth, async(req, res)=>{ try{ const deletedpost = await Post.findOneAndDelete({_id:req.params.id, user:req.user.id}) res.json({ deletedpost }) }catch(err){ return res.status(500).json({message:err.message}) } })
postConstants.js
export const DELETE_POST_REQUEST = 'DELETE_POST_REQUEST' export const DELETE_POST_SUCCESS = 'DELETE_POST_SUCCESS' export const DELETE_POST_FAIL = 'DELETE_POST_FAIL' export const DELETE_POST_RESET = 'DELETE_POST_RESET'
postActions.js
export const deletePost = (post) => async (dispatch, getState)=>{ dispatch({ type:DELETE_POST_REQUEST, payload:{loading:true} }) const {userLogin:{userInfo}} = getState() try{ const res = await axios.delete(`/api/post/${post._id}`, { headers:{authorization:`Bearer ${userInfo.token}`} }) console.log(res) dispatch({ type:DELETE_POST_SUCCESS, payload:res.data.deletedpost }) }catch(error){ dispatch({ type:DELETE_POST_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message }) } }
postReducer.js
export const postDeleteReducer = (state={}, action)=>{ switch(action.type){ case DELETE_POST_REQUEST: return {loading:true, success:false} case DELETE_POST_SUCCESS: return {loading:false, success:true, deletedpost:action.payload} case DELETE_POST_FAIL: return {loading:false, error:action.payload, success:false} case DELETE_POST_RESET: return {} default: return state } }
store.js
deletepost:postDeleteReducer,
cardHeader.js
const handleDeletePost= () =>{ dispatch(deletePost(post)) } <div className="dropdown-item"> <span className="material-icons" onClick = {handleDeletePost}>delete_outline</span> Remove Post </div>
Post.js
const deletepost = useSelector(state => state.deletepost) const {success:deletesuccess} = deletepost useEffect(() => { if(success||updatesuccess ||deletesuccess){ dispatch({type:GET_POSTS_RESET}) dispatch({type:CREATE_POST_RESET}) dispatch({type:UPDATE_POST_RESET}) dispatch({type:DELETE_POST_RESET}) } dispatch(getHomePosts()) }, [dispatch, success, updatesuccess, deletesuccess])
잘 삭제된다.
포스트를 삭제할때 comment도 삭제하도록 라우터를 수정해주자.
postRouter.delete('/:id', auth, async(req, res)=>{ try{ const deletedpost = await Post.findOneAndDelete({_id:req.params.id, user:req.user.id}) console.log(deletedpost._id) await Comment.deleteMany({postId: deletedpost._id}) res.json({ deletedpost }) }catch(err){ return res.status(500).json({message:err.message}) } })
헤더부분에 delete누르면 경고창이 뜨도록 추가해준다.
import {Link, useHistory} from 'react-router-dom' const handleDeletePost= () =>{ if(window.confirm("Are you wure want to delete this post?")){ dispatch(deletePost(post)) return history.push("/") } }
링크를 복사해주는 코드도 CardHeader에 추가해준다.
const handleCopyLink= () =>{ navigator.clipboard.writeText(`http://localhost:3000/post/${post._id}`) } <div className="dropdown-item" onClick={handleCopyLink}> <span className="material-icons">content_copy</span> Copy Link </div>
'NODE.JS' 카테고리의 다른 글
Social Media 만들기 - 15) create, like, update, delete comment 구현하기 (0) 2021.07.16 Social Media 만들기 - 14) like, unlike post 구현하기 (0) 2021.07.13 Social Media 만들기 - 12) get posts 가져오기 (0) 2021.07.12 req.body 가 undefined으로 뜰 때 (2) 2021.07.11 Social Media 만들기 - 11)createPost 작성하기 (0) 2021.07.11