From 11e4dba860e46640556850b93dfb9ee24c00e2fc Mon Sep 17 00:00:00 2001 From: nnyouung <104901660+nnyouung@users.noreply.github.com> Date: Mon, 22 Jul 2024 01:53:23 +0900 Subject: [PATCH] Feat/backend integration bookmark (#83) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 북마크 생성 백엔드 연결 및 변수명 직관적으로 변경 수정사항 - 북마크 생성 백엔드 연결 - api.js의 좋아요 생성 변수명 변경 (postHeart -> createLike) - PostPage의 handleHeart <-> handleHeart 변수명 변경 * feat: 좋아요 및 북마크한 게시물의 색상 변화가 유지되도록 수정 수정사항 - 사용자가 좋아요 및 북마크한 게시물의 색상 변화, 즉 상태가 유지되도록 수정 * fix: 서버 데이터 구조 변경에 따른 북마크한 글 조회 오류 수정 수정사항 - 모든 북마크 조회 api 서버 데이터 구조가 바뀜에 따라, 북마크한 글 조회를 할 수 있게 조건부로 수정 * style: Prettier & ESLint 적용 --- src/components/community/IconBookmark.jsx | 38 +++--- src/components/community/ItemComment.jsx | 6 +- src/components/member/ItemLikeBookmark.jsx | 12 +- src/config/api.js | 12 +- src/pages/community/PostPage.jsx | 139 ++++++++++++++++----- src/pages/member/BookmarkPostPage.jsx | 6 +- 6 files changed, 155 insertions(+), 58 deletions(-) diff --git a/src/components/community/IconBookmark.jsx b/src/components/community/IconBookmark.jsx index 4b0feedf..2129dc21 100644 --- a/src/components/community/IconBookmark.jsx +++ b/src/components/community/IconBookmark.jsx @@ -1,20 +1,26 @@ import * as React from "react"; import Svg, { Path } from "react-native-svg"; -const IconBookmark = (props) => ( - - - -); +import { CustomTheme } from "@styles/CustomTheme"; + +const IconBookmark = ({ props, active }) => { + const color = active ? CustomTheme.pointYellow : CustomTheme.borderColor; + return ( + + + + ); +}; + export default IconBookmark; diff --git a/src/components/community/ItemComment.jsx b/src/components/community/ItemComment.jsx index b1dfa24d..4f04ba4f 100644 --- a/src/components/community/ItemComment.jsx +++ b/src/components/community/ItemComment.jsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { View, Text, StyleSheet, TouchableOpacity, Alert } from "react-native"; import { CustomTheme } from "@styles/CustomTheme"; -import { postHeart } from "config/api"; +import { createLike } from "config/api"; import IconHeart from "@components/community/IconHeart"; import IconBookmark from "@components/community/IconBookmark"; @@ -32,7 +32,7 @@ const ItemComment = ({ props, id }) => { const heartCommentAlert = async (commentId) => { try { - await postHeart("COMMENT", id, commentId); + await createLike("COMMENT", id, commentId); console.log("댓글 좋아요 성공"); } catch (error) { console.error( @@ -125,7 +125,7 @@ const ItemComment = ({ props, id }) => { - {date(post.created)} + {date(post.date)} diff --git a/src/components/member/ItemLikeBookmark.jsx b/src/components/member/ItemLikeBookmark.jsx index ce378b0a..73777c61 100644 --- a/src/components/member/ItemLikeBookmark.jsx +++ b/src/components/member/ItemLikeBookmark.jsx @@ -6,7 +6,7 @@ import { CustomTheme } from "@styles/CustomTheme"; const { fontCaption, fontNavi } = CustomTheme; -const ItemLikeBookmark = ({ props }) => { +const ItemLikeBookmark = ({ props, type = "like" }) => { const navigation = useNavigation(); return ( @@ -27,7 +27,7 @@ const ItemLikeBookmark = ({ props }) => { post.image ? { width: 196 } : {}, ]} > - {post.title} + {type === "like" ? post.title : post.post.title} { post.image ? { width: 196 } : {}, ]} > - {post.content} + {type === "like" + ? post.content + : post.post.content} @@ -55,10 +57,10 @@ const ItemLikeBookmark = ({ props }) => { const styles = StyleSheet.create({ ItemCommunity: { width: "100%", - height: 78, + height: 62, backgroundColor: CustomTheme.bgBasic, borderRadius: 20, - borderWidth: 2, + borderWidth: 3, borderColor: CustomTheme.primaryBg, paddingHorizontal: 20, justifyContent: "center", diff --git a/src/config/api.js b/src/config/api.js index ff7e2af2..3c09decd 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -139,10 +139,18 @@ export const getCommentById = (id) => { return api.get(`comments/${id}`); }; -export const postHeart = (type, id, commentId) => { +export const createLike = (type, postId, commentId) => { return api.post("/likes", { type: type, - postId: id, + postId: postId, commentId: commentId, }); }; + +export const createBookmark = (chatroomId, chatId, postId) => { + return api.post("/bookmarks", { + chatroomId: chatroomId, + chatId: chatId, + postId: postId, + }); +}; diff --git a/src/pages/community/PostPage.jsx b/src/pages/community/PostPage.jsx index 341e7bff..85dc48a4 100644 --- a/src/pages/community/PostPage.jsx +++ b/src/pages/community/PostPage.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { TouchableOpacity, Text, @@ -12,16 +12,19 @@ import { Alert, } from "react-native"; import { useFocusEffect } from "@react-navigation/native"; -import * as SecureStore from "expo-secure-store"; import PostStyles from "@pages/community/PostStyles"; import { CustomTheme } from "@styles/CustomTheme"; +import { useOnboarding } from "src/states/OnboardingContext.js"; import { usePostModify } from "src/states/PostModifyContext"; import { getPostById, getCommentById, postCommentSend, - postHeart, + createLike, + createBookmark, + getLikedPost, + getBookmarkPost, } from "config/api"; import TopBar from "@components/common/TopBar"; @@ -39,6 +42,7 @@ const PostPage = ({ route }) => { const [modalVisible, setModalVisible] = useState(false); const { id } = route.params; + const { onboardingData } = useOnboarding(); const { updatePostModifyData } = usePostModify(); const [title, setTitle] = useState(""); @@ -70,31 +74,28 @@ const PostPage = ({ route }) => { const postComment = async () => { try { const postByIdResponse = await getPostById(id); - const postData = postByIdResponse.data; - setTitle(postData.title); - setContext(postData.content); - setHeart(postData.likesCount); - setBookmark(postData.bookmarkCount); - setCreated(date(postData.created)); - setIsPublic(postData.isPublic); - - if (postData.isPublic === false) { - setWriterName(postData.writer.username); - } else if (postData.isPublic === true) { + setTitle(postByIdResponse.data.title); + setContext(postByIdResponse.data.content); + setHeart(postByIdResponse.data.likesCount); + setBookmark(postByIdResponse.data.bookmarkCount); + setCreated(date(postByIdResponse.data.created)); + setIsPublic(postByIdResponse.data.isPublic); + + if (postByIdResponse.data.isPublic === false) { + setWriterName(postByIdResponse.data.writer.username); + } else if (postByIdResponse.data.isPublic === true) { setWriterName("익명"); } - const memberId = - await SecureStore.getItemAsync("member_id"); - if (memberId === postData.writer.id) { + if (onboardingData.id === postByIdResponse.data.writer.id) { setIsMe(true); updatePostModifyData({ - memberId: postData.writer.id, + memberId: postByIdResponse.data.writer.id, id: id, - title: postData.title, - context: postData.content, - boardType: postData.boardType, - isPublic: postData.isPublic, + title: postByIdResponse.data.title, + context: postByIdResponse.data.content, + boardType: postByIdResponse.data.boardType, + isPublic: postByIdResponse.data.isPublic, }); } @@ -104,7 +105,11 @@ const PostPage = ({ route }) => { console.log("게시글 및 댓글 조회 성공"); } catch (error) { console.error( - "게시글 및 댓글 조회 오류:", + "게시글 조회 오류:", + error.response ? error.response.data : error.message, + ); + console.error( + "댓글 조회 오류:", error.response ? error.response.data : error.message, ); } @@ -173,9 +178,9 @@ const PostPage = ({ route }) => { const [pressHeart, setPressHeart] = useState(); - const heartAlert = async () => { + const handleHeart = async () => { try { - await postHeart("POST", id); + await createLike("POST", id); console.log("게시글 좋아요 성공"); } catch (error) { console.error( @@ -187,7 +192,7 @@ const PostPage = ({ route }) => { } }; - const handleHeart = () => { + const heartAlert = () => { Alert.alert( "", "이 게시물에 좋아요를 누르시겠습니까?", @@ -201,7 +206,58 @@ const PostPage = ({ route }) => { onPress: () => { setHeart((prevHeart) => prevHeart + 1); setPressHeart(true); - heartAlert(); + handleHeart(); + }, + }, + ], + { cancelable: false }, + ); + }; + + const likedPosts = async () => { + try { + const response = await getLikedPost(); + const likedPostIdList = response.data.map((item) => item.id); + setPressHeart(likedPostIdList.includes(id)); + } catch (error) { + console.error( + "좋아요 상태 조회 실패:", + error.response ? error.response.data : error.message, + ); + } + }; + + const [pressBookmark, setPressBookmark] = useState(); + + const handleBookmark = async () => { + try { + await createBookmark(null, null, id); + console.log("게시글 북마크 성공"); + } catch (error) { + console.error( + "게시글 북마크 실패:", + error.response ? error.response.data : error.message, + ); + setBookmark((prevBookmark) => prevBookmark - 1); + setPressBookmark(false); + } + }; + + const bookmarkAlert = () => { + Alert.alert( + "", + "이 게시물을 북마크하시겠습니까?", + [ + { + text: "취소", + style: "cancel", + }, + { + text: "확인", + onPress: () => { + setBookmark((prevBookmark) => prevBookmark + 1); + setPressBookmark(true); + handleBookmark(); }, }, ], @@ -209,6 +265,24 @@ const PostPage = ({ route }) => { ); }; + const bookmarkedPosts = async () => { + try { + const response = await getBookmarkPost(); + const bookmarkedPostIdList = response.data.map((item) => item.id); + setPressBookmark(bookmarkedPostIdList.includes(id)); + } catch (error) { + console.error( + "북마크 상태 조회 실패:", + error.response ? error.response.data : error.message, + ); + } + }; + + useEffect(() => { + likedPosts(); + bookmarkedPosts(); + }, [id]); + return ( @@ -248,15 +322,18 @@ const PostPage = ({ route }) => { {heart} - - + + {bookmark} - + 번역하기 diff --git a/src/pages/member/BookmarkPostPage.jsx b/src/pages/member/BookmarkPostPage.jsx index a86acf91..6ae75786 100644 --- a/src/pages/member/BookmarkPostPage.jsx +++ b/src/pages/member/BookmarkPostPage.jsx @@ -14,6 +14,7 @@ const BookmarkPostPage = () => { try { const bookmarkPostResponse = await getBookmarkPost(); setBookmarkPostList(bookmarkPostResponse.data); + console.log(bookmarkPostResponse.data); } catch (error) { console.error( "북마크한 게시글 조회 오류:", @@ -28,7 +29,10 @@ const BookmarkPostPage = () => { - +