diff --git a/src/api/useGetComment.jsx b/src/api/useGetComment.jsx
index 2c97859..dd61976 100644
--- a/src/api/useGetComment.jsx
+++ b/src/api/useGetComment.jsx
@@ -80,12 +80,12 @@ export const getPostComments = async (postId) => {
}
};
-// transformCommentData 함수도 약간 수정
const transformCommentData = (commentData) => ({
id: commentData.id,
postId: commentData.postId,
parentId: commentData.parentId,
content: commentData.content,
+ clean: commentData.clean ?? true, // clean 필드 추가, 기본값은 true
depth: commentData.depth,
createdAt: commentData.createdAt,
updatedAt: commentData.updatedAt,
@@ -94,5 +94,5 @@ const transformCommentData = (commentData) => ({
name: commentData.member.name,
nameEnglish: commentData.member.nameEnglish,
},
- replies: [], // 초기 replies 배열 추가
+ replies: [],
});
diff --git a/src/api/useGetPost.jsx b/src/api/useGetPost.jsx
index 700377c..254f9de 100644
--- a/src/api/useGetPost.jsx
+++ b/src/api/useGetPost.jsx
@@ -23,6 +23,7 @@ export const getPost = async (postId) => {
"createdAt",
"updatedAt",
"member",
+ "clean", // clean 필드로 수정
];
for (const field of requiredFields) {
@@ -45,9 +46,10 @@ export const getPost = async (postId) => {
content: postData.content,
createdAt: postData.createdAt,
updatedAt: postData.updatedAt,
- imageUrls: postData.cloudFrontPaths || [], // cloudFrontPath 사용
- s3ImageUrls: postData.s3ImagePaths || [], // s3ImagePaths 보관
+ imageUrls: postData.cloudFrontPaths || [],
+ s3ImageUrls: postData.s3ImagePaths || [],
likes: (postData.likes !== undefined ? postData.likes : 0).toString(),
+ clean: postData.clean, // clean 필드로 수정
author: {
id: postData.member.id,
role: postData.member.role,
@@ -66,57 +68,3 @@ export const getPost = async (postId) => {
throw error;
}
};
-
-// useGetPosts.jsx
-export const getPosts = async (pageNo = 0, pageSize = 10) => {
- try {
- const response = await api.get("/api/v1/posts", {
- params: {
- pageNo,
- pageSize,
- },
- });
-
- const transformedData = {
- content: response.data.content.map((post) => ({
- post_id: post.id,
- post_title: post.title,
- post_content: post.content,
- created_at: post.createdAt,
- updated_at: post.updatedAt,
- member: {
- member_id: post.member.id,
- member_name: post.member.name,
- member_name_english: post.member.nameEnglish,
- course: post.member.course,
- role: post.member.role,
- },
- // cloudFrontPaths 사용
- imageUrls: post.cloudFrontPaths || [],
- // 첫 번째 이미지를 대표 이미지로 사용
- mainImageUrl: post.cloudFrontPaths?.[0] || "",
- // S3 URL도 보관
- s3ImageUrls: post.s3ImagePaths || [],
- })),
- totalPages: response.data.totalPages,
- totalElements: response.data.totalElements,
- size: response.data.size,
- number: response.data.number,
- first: response.data.first,
- last: response.data.last,
- };
-
- return transformedData;
- } catch (error) {
- console.error("Error fetching posts:", error);
- return {
- content: [],
- totalPages: 0,
- totalElements: 0,
- size: pageSize,
- number: pageNo,
- first: true,
- last: true,
- };
- }
-};
diff --git a/src/api/useGetPosts.jsx b/src/api/useGetPosts.jsx
index 5bb76ef..75b3c34 100644
--- a/src/api/useGetPosts.jsx
+++ b/src/api/useGetPosts.jsx
@@ -10,23 +10,31 @@ export const getPosts = async (pageNo = 0, pageSize = 10) => {
},
});
- // API 응답을 데이터베이스 스키마에 맞게 변환
+ console.log("API Response:", response.data); // API 응답 로깅 추가
+
const transformedData = {
- content: response.data.content.map((post) => ({
- post_id: post.id,
- post_title: post.title,
- post_content: post.content,
- created_at: post.createdAt,
- updated_at: post.updatedAt,
- member: {
- member_id: post.member.id,
- member_name: post.member.name,
- member_name_english: post.member.nameEnglish,
- course: post.member.course,
- role: post.member.role,
- },
- imageUrls: post.imageUrls || [],
- })),
+ content: response.data.content.map((post) => {
+ console.log("Individual post data:", post); // 개별 게시물 데이터 로깅
+ return {
+ post_id: post.id,
+ post_title: post.title,
+ post_content: post.content,
+ created_at: post.createdAt,
+ updated_at: post.updatedAt,
+ clean: post.clean === undefined ? true : post.clean, // clean 필드 처리 수정
+ member: {
+ member_id: post.member.id,
+ member_name: post.member.name,
+ member_name_english: post.member.nameEnglish,
+ course: post.member.course,
+ role: post.member.role,
+ },
+ imageUrls: post.cloudFrontPaths || [],
+ mainImageUrl: post.cloudFrontPaths?.[0] || "",
+ s3ImageUrls: post.s3ImagePaths || [],
+ likes: post.likes?.toString() || "0",
+ };
+ }),
totalPages: response.data.totalPages,
totalElements: response.data.totalElements,
size: response.data.size,
@@ -35,6 +43,8 @@ export const getPosts = async (pageNo = 0, pageSize = 10) => {
last: response.data.last,
};
+ console.log("Transformed data:", transformedData); // 변환된 데이터 로깅
+
return transformedData;
} catch (error) {
console.error("Error fetching posts:", error);
diff --git a/src/component/ FilteredComment.jsx b/src/component/ FilteredComment.jsx
new file mode 100644
index 0000000..f072772
--- /dev/null
+++ b/src/component/ FilteredComment.jsx
@@ -0,0 +1,35 @@
+import { useState } from "react";
+import PropTypes from "prop-types";
+import "./styles/FilteredComment.scss";
+
+const FilteredCommentContent = ({ content, clean = true }) => {
+ const [isRevealed, setIsRevealed] = useState(false);
+
+ if (clean) {
+ return
{content}
;
+ }
+
+ return (
+
+ {!isRevealed ? (
+
+
+ [구름봇에 의해 가려진 댓글입니다]
+
+
+
+ ) : (
+
{content}
+ )}
+
+ );
+};
+
+FilteredCommentContent.propTypes = {
+ content: PropTypes.string.isRequired,
+ clean: PropTypes.bool,
+};
+
+export default FilteredCommentContent;
diff --git a/src/component/Comment.jsx b/src/component/Comment.jsx
index 2730888..8a73395 100644
--- a/src/component/Comment.jsx
+++ b/src/component/Comment.jsx
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
import { MoreHorizontal } from "lucide-react";
import CommentInput from "./CommentInput";
import { getCommentDetail } from "../api/useGetCommentDetail";
+import FilteredCommentContent from "./ FilteredComment";
import {
useCreateComment,
useEditComment,
@@ -255,7 +256,10 @@ const Comment = ({
) : (
<>
- {comment.content}
+
{formatDate(comment.createdAt)}
@@ -310,6 +314,7 @@ Comment.propTypes = {
comment: PropTypes.shape({
id: PropTypes.number.isRequired,
content: PropTypes.string.isRequired,
+ clean: PropTypes.bool, // clean 필드 추가
createdAt: PropTypes.string.isRequired,
parentId: PropTypes.number,
depth: PropTypes.number.isRequired,
diff --git a/src/component/FilteredContent.jsx b/src/component/FilteredContent.jsx
new file mode 100644
index 0000000..7874fb6
--- /dev/null
+++ b/src/component/FilteredContent.jsx
@@ -0,0 +1,44 @@
+import { useState } from "react";
+import PropTypes from "prop-types";
+import "./styles/FilteredContent.scss";
+
+const FilteredContent = ({ title, content, clean = true }) => {
+ const [isRevealed, setIsRevealed] = useState(false);
+
+ if (clean) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {!isRevealed ? (
+
+
+ [구름봇에 의해 가려진 게시물입니다]
+
+
+
+ ) : (
+
+ )}
+
+ );
+};
+
+FilteredContent.propTypes = {
+ title: PropTypes.string.isRequired,
+ content: PropTypes.string.isRequired,
+ clean: PropTypes.bool,
+};
+
+export default FilteredContent;
diff --git a/src/component/Postlist.jsx b/src/component/Postlist.jsx
index 57f646c..47d7332 100644
--- a/src/component/Postlist.jsx
+++ b/src/component/Postlist.jsx
@@ -1,8 +1,9 @@
import PropTypes from "prop-types";
import "./styles/Postlist.scss";
import Hearticon from "../image/Hearticon.svg";
-//pr test
-const Postlist = ({ id, title, imageUrl, likes }) => {
+import SimpleFilteredContent from "./SimpleFilteredContent";
+
+const Postlist = ({ id, title, imageUrl = "", likes, clean = true }) => {
return (
@@ -13,14 +14,16 @@ const Postlist = ({ id, title, imageUrl, likes }) => {
onError={(e) => {
console.error("Image load error:", imageUrl);
e.target.onerror = null;
- e.target.src = "/default-image.png"; // 기본 이미지 경로
+ e.target.src = "/default-image.png";
}}
/>
) : (
)}
-
{title}
+
+
+
@@ -35,10 +38,7 @@ Postlist.propTypes = {
title: PropTypes.string.isRequired,
imageUrl: PropTypes.string,
likes: PropTypes.string.isRequired,
-};
-
-Postlist.defaultProps = {
- imageUrl: "",
+ clean: PropTypes.bool,
};
export default Postlist;
diff --git a/src/component/SimpleFilteredContent.jsx b/src/component/SimpleFilteredContent.jsx
new file mode 100644
index 0000000..b894659
--- /dev/null
+++ b/src/component/SimpleFilteredContent.jsx
@@ -0,0 +1,20 @@
+import PropTypes from "prop-types";
+
+const SimpleFilteredContent = ({ content, clean = true }) => {
+ if (clean) {
+ return
{content}
;
+ }
+
+ return (
+
+ [구름봇에 의해 가려졌습니다]
+
+ );
+};
+
+SimpleFilteredContent.propTypes = {
+ content: PropTypes.string.isRequired,
+ clean: PropTypes.bool,
+};
+
+export default SimpleFilteredContent;
diff --git a/src/component/ViewPage.jsx b/src/component/ViewPage.jsx
index 123ebc4..60802e4 100644
--- a/src/component/ViewPage.jsx
+++ b/src/component/ViewPage.jsx
@@ -10,6 +10,7 @@ import { deletePost } from "../api/useDeletePost";
import WriteForm from "../containers/WriteForm";
import CommentInput from "./CommentInput";
import { useCreateComment } from "../hooks/useComment";
+import FilteredContent from "./FilteredContent";
const ViewPage = ({
post,
@@ -257,8 +258,11 @@ const ViewPage = ({
)}
-
제목: {post.title}
-
{post.content}
+
{post.likes}
@@ -310,6 +314,7 @@ ViewPage.propTypes = {
imageUrl: PropTypes.string,
likes: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
+ clean: PropTypes.bool.isRequired, // isClean에서 clean으로 변경
author: PropTypes.shape({
id: PropTypes.number.isRequired,
role: PropTypes.string.isRequired,
diff --git a/src/component/styles/Comment.scss b/src/component/styles/Comment.scss
index c8be962..31a4385 100644
--- a/src/component/styles/Comment.scss
+++ b/src/component/styles/Comment.scss
@@ -5,7 +5,7 @@
margin-bottom: 15px;
.comment-header {
- margin-bottom: 8px;
+ margin-bottom: 0px;
.author-line {
display: flex;
@@ -55,7 +55,8 @@
}
.comment-content {
- margin: 8px 0;
+ margin-top: 3px;
+ margin-bottom: 8px;
word-break: break-word;
}
diff --git a/src/component/styles/FilteredComment.scss b/src/component/styles/FilteredComment.scss
new file mode 100644
index 0000000..c02b245
--- /dev/null
+++ b/src/component/styles/FilteredComment.scss
@@ -0,0 +1,44 @@
+.filtered-comment {
+ background-color: #f8f9fa;
+ border-radius: 4px;
+ overflow: hidden;
+
+ .filtered-message {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0;
+
+ .warning-text {
+ color: #6c757d;
+ font-size: 0.9rem;
+ flex: 1;
+ }
+
+ .reveal-button {
+ padding: 0.25rem 0.75rem;
+ background-color: #3f51b5;
+ border: none;
+ border-radius: 15px;
+ color: white;
+ font-size: 0.8rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease-in-out;
+
+ &:hover {
+ background-color: #303f9f;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ &:active {
+ transform: translateY(1px);
+ }
+ }
+ }
+
+ .comment-content {
+ padding: 0;
+ word-break: break-word;
+ }
+}
diff --git a/src/component/styles/FilteredContent.scss b/src/component/styles/FilteredContent.scss
new file mode 100644
index 0000000..5899cc9
--- /dev/null
+++ b/src/component/styles/FilteredContent.scss
@@ -0,0 +1,58 @@
+// FilteredContent.scss
+.filtered-content {
+ width: 100%;
+ background-color: white;
+ border-radius: 8px;
+ margin: 0; // 여백 제거
+ padding: 0; // 여백 제거
+
+ .filtered-message {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ text-align: center;
+ padding: 1rem; // 내부 여백만 유지
+
+ .warning-text {
+ color: #6c757d;
+ font-size: 1rem;
+ font-weight: 500;
+ }
+
+ .reveal-button {
+ padding: 0.5rem 1.5rem;
+ background-color: #3f51b5;
+ border: none;
+ border-radius: 20px;
+ color: white;
+ font-size: 0.9rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease-in-out;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+ &:hover {
+ background-color: #303f9f;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
+
+ &:active {
+ transform: translateY(0);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+ }
+ }
+}
+
+// Postlist용 심플 스타일
+.simple-filtered-content {
+ padding: 0;
+ margin: 0;
+
+ .warning-text {
+ color: #6c757d;
+ font-size: 0.9rem;
+ }
+}
diff --git a/src/component/styles/ViewPage.scss b/src/component/styles/ViewPage.scss
index d9a7189..94d8de9 100644
--- a/src/component/styles/ViewPage.scss
+++ b/src/component/styles/ViewPage.scss
@@ -99,10 +99,12 @@
font-size: 1.2em;
font-weight: bold;
margin-bottom: 10px;
+ padding: 0;
}
.content {
margin-bottom: 15px;
+ padding: 0;
}
.reaction {
diff --git a/src/containers/Community.jsx b/src/containers/Community.jsx
index 4dc88f5..1e88ccf 100644
--- a/src/containers/Community.jsx
+++ b/src/containers/Community.jsx
@@ -59,6 +59,7 @@ const Community = () => {
post_likes: 0,
created_at: newPost.createdAt,
updated_at: newPost.updatedAt,
+ clean: newPost.clean, // clean 필드 추가
member: newPost.member,
};
@@ -76,7 +77,6 @@ const Community = () => {
setCurrentPage(0);
};
- // Community.jsx
const handleCommentsUpdate = async (updatedComments) => {
try {
console.log("Received updated comments:", updatedComments);
@@ -139,6 +139,7 @@ const Community = () => {
post_likes: post.post_likes,
created_at: updatedPost.createdAt,
updated_at: updatedPost.updatedAt,
+ clean: updatedPost.clean, // clean 필드 추가
member: updatedPost.member,
}
: post
@@ -239,6 +240,7 @@ const Community = () => {
? post.post_likes
: 0
).toString()}
+ clean={post.clean} // clean prop 추가
/>
))
diff --git a/src/containers/PostForm.jsx b/src/containers/PostForm.jsx
index b8fb7b1..927fc88 100644
--- a/src/containers/PostForm.jsx
+++ b/src/containers/PostForm.jsx
@@ -6,11 +6,11 @@ import Commenticon from "../image/Commenticon.svg";
import FullHearticon from "../image/FullHearticon.svg";
import Comment from "../component/Comment";
import CommentInput from "../component/CommentInput";
+import FilteredContent from "../component/FilteredContent";
import { useCreateComment } from "../hooks/useComment";
import { getPostComments } from "../api/useGetComment";
const Post = ({ post, currentUserId }) => {
- // currentUserId prop 추가
const [isLiked, setIsLiked] = useState(false);
const [likeCount, setLikeCount] = useState(0);
const [comments, setComments] = useState([]);
@@ -151,7 +151,11 @@ const Post = ({ post, currentUserId }) => {
[{post.member.course}]
-
{post.post_content}
+
{post.imageUrls && post.imageUrls.length > 0 && (
{post.imageUrls.map((url, index) => (
@@ -217,8 +221,9 @@ Post.propTypes = {
post_content: PropTypes.string.isRequired,
created_at: PropTypes.string.isRequired,
updated_at: PropTypes.string.isRequired,
- imageUrls: PropTypes.arrayOf(PropTypes.string), // 이미지 URL 배열 추가
- s3ImageUrls: PropTypes.arrayOf(PropTypes.string), // S3 URL 배열 추가
+ clean: PropTypes.bool, // clean 필드 추가
+ imageUrls: PropTypes.arrayOf(PropTypes.string),
+ s3ImageUrls: PropTypes.arrayOf(PropTypes.string),
member: PropTypes.shape({
member_id: PropTypes.number.isRequired,
member_name: PropTypes.string.isRequired,
@@ -232,8 +237,10 @@ Post.propTypes = {
Post.defaultProps = {
post: {
- imageUrls: [], // 기본값 설정
- s3ImageUrls: [], // 기본값 설정
+ imageUrls: [],
+ s3ImageUrls: [],
+ clean: true, // clean의 기본값 추가
},
};
+
export default Post;
diff --git a/src/containers/styles/ChangePass.scss b/src/containers/styles/ChangePass.scss
index facdbe6..57d9a5b 100644
--- a/src/containers/styles/ChangePass.scss
+++ b/src/containers/styles/ChangePass.scss
@@ -17,6 +17,7 @@
}
.content-wrapper {
+ width: 100%;
h3 {
text-align: center;
margin: 20px 0; // 위아래 여백 추가