ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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)}>&times;</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>

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.