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
게시물 삭제 후 게시물 목록 불러 올 때 참고한 문서
https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0
2. 게시물 관련된 문서 삭제하는 기능
: 실제로 구현하지는 못했지만, 시간 날 때 구현 해보면 될 것 같다.
https://firebase.google.com/docs/firestore/manage-data/delete-data?authuser=0
https://firebase.google.com/docs/storage/web/delete-files?authuser=0
'항해 중 > 5주차 리액트 심화반' 카테고리의 다른 글
5주차 - SEO란(검색 엔진 최적화)? (0) | 2021.12.04 |
---|---|
5주차 - 프로젝트 호스팅 하기 (0) | 2021.12.04 |
추가 - 좋아요 기능 (0) | 2021.12.03 |
4주차 - 엔터 키로 입력하기 (1) | 2021.12.03 |
4주차 - 댓글 알림 뱃지 만들기 (0) | 2021.12.03 |
댓글