추가 - 삭제 기능
본문 바로가기
항해 중/5주차 리액트 심화반

추가 - 삭제 기능

by 은돌1113 2021. 12. 3.

1. 게시물만 삭제하는 기능

// Post.js

import React from "react";
import { Grid, Image, Text, Button } from "../elements";
import { history } from "../redux/configureStore";
import styled from "styled-components";
import Permit from "../shared/Permit";
import { useSelector, useDispatch } from "react-redux";
import { actionCreators as likeActions } from "../redux/modules/like";
import { actionCreators as postActions } from "../redux/modules/post";

const Post = (props) => {
  const user_id = useSelector((state) => state.user.user?.uid);
  const post = useSelector((state) => state.post.list);

  const [like, setLike] = React.useState(false);
  const [color, setColor] = React.useState("unLike");
  const styles = { color: color };

  const dispatch = useDispatch();

  // 좋아요 유무에 따라서 새로고침이 되어도 그대로 반영 되게 하는 코드
  React.useEffect(() => {
    const _post = post.filter((p) => {
      // 게시물 정보에서 좋아요를 누른 사람의 목록을 가져온다.
      return p.id === props.id;
    })[0].like_list;

    if (_post) {
      _post.forEach((p) => {
        if (p === user_id) {
          setLike(true);
          setColor("like");
        }
      });
    }
  });

  const likeClick = (props) => {
    const post_id = props.id; // 게시물 정보
    const like_cnt = props.like_cnt; // 좋아요 갯수
    const post_user_id = props.user_info.user_id; // 게시물 작성자
    const like_list = props.like_list; // 좋아요 누른 사람들 아이디

    // 게시물 작성자인 지 체크
    if (post_user_id === user_id) {
      window.alert("작성자의 게시물에는 좋아요를 누르실 수 없습니다.");
      return;
    }
    // else if(like_list.includes(user_id)){ // 이게 진짜 필요할까??
    //   window.alert("이미 좋아요를 눌렀습니다.")
    //   return;
    // }

    if (like) {
      // 안좋아요
      setLike(false);
      setColor("unLike");
      // 좋아요 해제하면 firebase, redux에 like_cnt - 1
      dispatch(likeActions.minusLikeFB(post_id, like_cnt, like_list));
    } else {
      // 좋아요
      setLike(true);
      setColor("like");
      // 좋아요를 누르면 firebase, redux에 like_cnt + 1
      dispatch(likeActions.addLikeFB(post_id, like_cnt, like_list));
    }
  };

  const postDel = (post_id) => {
    dispatch(postActions.deletePostFB(post_id))
  }

  return (
    <React.Fragment>
      <Grid>
        <Grid is_flex padding="16px">
          <Grid is_flex width="auto">
            <Image shape="circle" src={props.user_profile}></Image>
            <Text bold>{props.user_info.user_name}</Text>
          </Grid>
          <Grid is_flex width="auto">
            <Text>{props.insert_dt}</Text>
            {props.is_me && (
              <Button
                width="auto"
                padding="4px"
                margin="4px"
                _onClick={() => {
                  history.push(`/postWrite/${props.id}`);
                }}
              >
                수정
              </Button>
            )}
            {props.is_me && (
              <Button
                width="auto"
                padding="4px"
                margin="4px"
                _onClick={() => {
                  postDel(props.id)
                }}
              >
                삭제
              </Button>
            )}
          </Grid>
        </Grid>
        <Grid
          _onClick={() => {
            history.push(`postDetail/${props.id}`);
          }}
        >
          <Grid padding="16px">
            <Text>{props.contents}</Text>
          </Grid>
          <Grid>
            <Image shape="rectangle" src={props.image_url}></Image>
          </Grid>
        </Grid>
        <Grid padding="16px" is_flex>
          <Text bold>댓글 {props.comment_cnt}개</Text>
          <Text bold>좋아요 {props.like_cnt}개</Text>
          <Permit>
            {/* 좋아요 유무 */}
            <Like
              {...styles}
              onClick={() => {
                likeClick(props);
              }}
            >
              ♥
            </Like>
          </Permit>
        </Grid>
      </Grid>
    </React.Fragment>
  );
};

Post.defaultProps = {
  user_info: {
    user_name: "오새봄",
    user_profile: "https://i.ytimg.com/vi/Ct1Pp_4FEIY/maxresdefault.jpg",
  },
  image_url: "https://i.ytimg.com/vi/Ct1Pp_4FEIY/maxresdefault.jpg",
  contents: "오새봄이다. 찬양해라",
  comment_cnt: 10,
  insert_dt: "2021-11-29 19:09:00",
};

const Like = styled.div`
  // ***
  font-size: 30px;
  color: ${(props) => (props.color === "like" ? "pink" : "gray")};
`;

export default Post;
// post.js

import { createAction, handleActions } from "redux-actions";
import { produce } from "immer";
import { firestore, storage } from "../../shared/firebase";
import firebase from "firebase/compat/app";
import "moment";
import moment from "moment";

import { actionCreators as imageActions } from "./image";

// 액션 타입
const SET_POST = "SET_POST";
const ADD_POST = "ADD_POST";
const EDIT_POST = "EDIT_POST";
const DELETE_POST = "DELETE_POST";
const LOADING = "LOADING";

// 액션 생성 함수
const setPost = createAction(SET_POST, (post_list, paging) => ({
  post_list,
  paging,
}));
const addPost = createAction(ADD_POST, (post) => ({ post }));
const editPost = createAction(EDIT_POST, (post_id, post) => ({
  post_id,
  post,
}));
const deletePost = createAction(DELETE_POST, (post_list) => ({ post_list }));
const loading = createAction(LOADING, (is_loading) => ({ is_loading }));

// 초기값
const initialState = {
  list: [],
  paging: { start: null, next: null, size: 3 },
  is_loading: false,
};

const initialPost = {
  // id: 0,
  // user_info: {
  //   user_name: "mean0",
  //   user_profile: "https://mean0images.s3.ap-northeast-2.amazonaws.com/4.jpeg",
  // },
  image_url: "https://mean0images.s3.ap-northeast-2.amazonaws.com/4.jpeg",
  contents: "",
  comment_cnt: 0,
  like_cnt: 0,
  like_list: [],
  insert_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
};

const deletePostFB = (post_id = null) => {
  return function (dispatch, getState, { history }) {
    if (!post_id) {
      console.log("게시물 정보가 없어요!");
      return;
    }

    const postDB = firestore.collection("post");

    postDB
      .doc(post_id)
      .delete()
      .then((doc) => {
        console.log("게시물 삭제 성공");
        postDB
          .get()
          .then((docs) => {
            const post_list = [];

            docs.forEach((doc) => {
              post_list.push(doc.data());
            });
            dispatch(deletePost(post_list));
            window.location.reload()
          })
          .catch((err) => {
            console.log("게시물 삭제 실패", err);
          });
      });
  };
};

const editPostFB = (post_id = null, post = {}) => {
  return function (dispatch, getState, { history }) {
    if (!post_id) {
      console.log("게시물 정보가 없어요!");
      return;
    }

    const _image = getState().image.preview;

    const _post_idx = getState().post.list.findIndex((p) => p.id === post_id);
    const _post = getState().post.list[_post_idx];

    const postDB = firestore.collection("post");

    if (_image === _post.image_url) {
      postDB
        .doc(post_id)
        .update(post)
        .then((doc) => {
          dispatch(editPost(post_id, { ...post }));
          history.replace("/");
        });

      return;
    } else {
      const user_id = getState().user.user.uid;
      const _upload = storage
        .ref(`images/${user_id}_${new Date().getTime()}`)
        .putString(_image, "data_url");

      _upload.then((snapshot) => {
        snapshot.ref
          .getDownloadURL()
          .then((url) => {
            return url;
          })
          .then((url) => {
            postDB
              .doc(post_id)
              .update({ ...post, image_url: url })
              .then((doc) => {
                dispatch(editPost(post_id, { ...post, image_url: url }));
                history.replace('/')
              });
          })
          .catch((err) => {
            window.alert("앗! 이미지 업로드에 문제가 있어요!");
            console.log("앗! 이미지 업로드에 문제가 있어요!", err);
          });
      });
    }
  };
};

const addPostFB = (contents = "") => {
  return function (dispatch, getState, { history }) {
    const postDB = firestore.collection("post");

    const _user = getState().user.user;

    const user_info = {
      user_name: _user.user_name,
      user_id: _user.uid,
      user_profile: _user.user_profile,
    };

    const _post = {
      ...initialPost,
      contents: contents,
      insert_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
    };

    const _image = getState().image.preview;

    console.log(_image);
    console.log(typeof _image);

    const _upload = storage
      .ref(`images/${user_info.user_id}_${new Date().getTime()}`)
      .putString(_image, "data_url");

    _upload.then((snapshot) => {
      snapshot.ref
        .getDownloadURL()
        .then((url) => {
          return url;
        })
        .then((url) => {
          postDB
            .add({ ...user_info, ..._post, image_url: url })
            .then((doc) => {
              let post = { user_info, ..._post, id: doc.id, image_url: url };
              dispatch(addPost(post));
              history.replace("/");

              dispatch(imageActions.setPreview(null));
            })
            .catch((err) => {
              window.alert("앗! 포스트 작성에 문제가 있어요!");
              console.log("post 작성에 실패했어요!", err);
            });
        })
        .catch((err) => {
          window.alert("앗! 이미지 업로드에 문제가 있어요!");
          console.log("앗! 이미지 업로드에 문제가 있어요!", err);
        });
    });
  };
};

const getPostFB = (start = null, size = 3) => {
  return function (dispatch, getState, { history }) {
    let _paging = getState().post.paging;

    if (_paging.start && !_paging.next) {
      return;
    }

    dispatch(loading(true));
    const postDB = firestore.collection("post");

    let query = postDB.orderBy("insert_dt", "desc");

    if (start) {
      query = query.startAt(start);
    }

    query
      .limit(size + 1)
      .get()
      .then((docs) => {
        let post_list = [];

        let paging = {
          start: docs.docs[0],
          next:
            docs.docs.length === size + 1
              ? docs.docs[docs.docs.length - 1]
              : null,
          size: size,
        };

        docs.forEach((doc) => {
          let _post = doc.data();

          // ['commenct_cnt', 'contents', ..]
          let post = Object.keys(_post).reduce(
            (acc, cur) => {
              if (cur.indexOf("user_") !== -1) {
                return {
                  ...acc,
                  user_info: { ...acc.user_info, [cur]: _post[cur] },
                };
              }
              return { ...acc, [cur]: _post[cur] };
            },
            { id: doc.id, user_info: {} }
          );

          post_list.push(post);
        });

        post_list.pop();

        dispatch(setPost(post_list, paging));
      });
  };
};

const getOnePostFB = (id) => {
  return function (dispatch, getState, { history }) {
    const postDB = firestore.collection("post");
    postDB
      .doc(id)
      .get()
      .then((doc) => {
        console.log(doc);
        console.log(doc.data());

        let _post = doc.data();
        let post = Object.keys(_post).reduce(
          (acc, cur) => {
            if (cur.indexOf("user_") !== -1) {
              return {
                ...acc,
                user_info: { ...acc.user_info, [cur]: _post[cur] },
              };
            }
            return { ...acc, [cur]: _post[cur] };
          },
          { id: doc.id, user_info: {} }
        );

        dispatch(setPost([post]));
      });
  };
};

export default handleActions(
  {
    [SET_POST]: (state, action) =>
      produce(state, (draft) => {
        draft.list.push(...action.payload.post_list);

        // post_id가 같은 중복 항목을 제거합시다! :)
        draft.list = draft.list.reduce((acc, cur) => {
          // findIndex로 누산값(cur)에 현재값이 이미 들어있나 확인해요!
          // 있으면? 덮어쓰고, 없으면? 넣어주기!
          if (acc.findIndex((a) => a.id === cur.id) === -1) {
            return [...acc, cur];
          } else {
            acc[acc.findIndex((a) => a.id === cur.id)] = cur;
            return acc;
          }
        }, []);

        // paging이 있을 때만 넣기
        if (action.payload.paging) {
          draft.paging = action.payload.paging;
        }
        draft.is_loading = false;
      }),

    [ADD_POST]: (state, action) =>
      produce(state, (draft) => {
        draft.list.unshift(action.payload.post);
      }),
    [EDIT_POST]: (state, action) =>
      produce(state, (draft) => {
        let idx = draft.list.findIndex((p) => p.id === action.payload.post_id);

        draft.list[idx] = { ...draft.list[idx], ...action.payload.post };
      }),
    [DELETE_POST]: (state, action) => {
      produce(state, (draft) => {
        draft.list = action.payload.post_list;
      });
    },
    [LOADING]: (state, action) =>
      produce(state, (draft) => {
        draft.is_loading = action.payload.is_loading;
      }),
  },
  initialState
);

const actionCreators = {
  setPost,
  addPost,
  editPost,
  getPostFB,
  addPostFB,
  editPostFB,
  getOnePostFB,
  deletePostFB,
};

export { actionCreators };

 

게시물 삭제 할 때 참고한 문서

https://firebase.google.com/docs/firestore/manage-data/delete-data?authuser=0 

 

Cloud Firestore에서 데이터 삭제  |  Firebase Documentation

Catch up on everthing we announced at this year's Firebase Summit. Learn more 의견 보내기 Cloud Firestore에서 데이터 삭제 다음 예시는 문서, 필드, 컬렉션을 삭제하는 방법을 보여줍니다. 문서 삭제 문서를 삭제하려

firebase.google.com

 

게시물 삭제 후 게시물 목록 불러 올 때 참고한 문서

https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0 

 

Cloud Firestore로 데이터 가져오기  |  Firebase Documentation

Catch up on everthing we announced at this year's Firebase Summit. Learn more 의견 보내기 Cloud Firestore로 데이터 가져오기 두 가지 방법으로 Cloud Firestore에 저장된 데이터를 검색할 수 있습니다. 문서, 문서 컬렉션

firebase.google.com


2. 게시물 관련된 문서 삭제하는 기능

: 실제로 구현하지는 못했지만, 시간 날 때 구현 해보면 될 것 같다.

 

https://firebase.google.com/docs/firestore/manage-data/delete-data?authuser=0 

 

Cloud Firestore에서 데이터 삭제  |  Firebase Documentation

Catch up on everthing we announced at this year's Firebase Summit. Learn more 의견 보내기 Cloud Firestore에서 데이터 삭제 다음 예시는 문서, 필드, 컬렉션을 삭제하는 방법을 보여줍니다. 문서 삭제 문서를 삭제하려

firebase.google.com

 

https://firebase.google.com/docs/storage/web/delete-files?authuser=0 

 

웹에서 파일 삭제  |  Firebase

Google은 흑인 공동체를 위한 인종적 평등을 추구하기 위해 노력하고 있습니다. 자세히 알아보기 의견 보내기 웹에서 파일 삭제 Cloud Storage에 파일을 업로드한 후 파일을 삭제할 수도 있습니다. 참

firebase.google.com

 

댓글