diff --git a/src/common/apis/post.tsx b/src/common/apis/post.tsx
index 903f67e..ff6a14c 100644
--- a/src/common/apis/post.tsx
+++ b/src/common/apis/post.tsx
@@ -1,12 +1,15 @@
import axiosApi from "./AxiosApi.tsx";
-import {PostListRequest, PostRequest, PostSearchRequest, PostUpdateRequest} from "../types/post.tsx";
+import {PostFolderRequest, PostListRequest, PostRequest, PostSearchRequest, PostUpdateRequest} from "../types/post.tsx";
import {postListRequestToParameter, postListSearchRequestToParameter} from "../util/url.tsx";
export const createPost = async (postRequest: PostRequest) =>
await axiosApi.post("/post", postRequest);
export const updatePost = async (postUpdateRequest: PostUpdateRequest) =>
- await axiosApi.patch(`/post`, postUpdateRequest);
+ await axiosApi.patch("/post", postUpdateRequest);
+
+export const updatePostFolder = async (postFolderRequest: PostFolderRequest) =>
+ await axiosApi.patch("/post/folder", postFolderRequest);
export const deletePost = async (id: string) =>
await axiosApi.patch(`/post/delete/${id}`);
diff --git a/src/common/types/blog.tsx b/src/common/types/blog.tsx
index 1306184..87de640 100644
--- a/src/common/types/blog.tsx
+++ b/src/common/types/blog.tsx
@@ -75,7 +75,7 @@ export const toFolderRequestList = (folderTypeList: FolderType[]) => {
export interface PostListMemberRequest {
username: string,
- folderId: string | null,
+ folderIds: string[] | null,
page: number,
size: number,
}
\ No newline at end of file
diff --git a/src/common/types/post.tsx b/src/common/types/post.tsx
index bb9b05c..c13a32a 100644
--- a/src/common/types/post.tsx
+++ b/src/common/types/post.tsx
@@ -3,6 +3,7 @@ import {PageResponse} from "./common.tsx";
export interface PostRequest {
title: string,
content: string,
+ folderId: string | null,
tagNames: string[],
urls: string[],
}
@@ -11,6 +12,7 @@ export interface PostUpdateRequest {
id: string,
title: string,
content: string,
+ folderId: string | null,
tagNames: string[],
urls: string[],
}
@@ -41,12 +43,22 @@ export interface PostResponse {
title: string;
content: string;
username: string;
+ folder?: PostFolderResponse;
tags: TagResponse[];
createdAt: Date;
}
+export interface PostFolderResponse {
+ id: string;
+ title: string;
+}
+
export interface TagResponse {
id: string;
name: string;
}
+export interface PostFolderRequest {
+ postIds: string[],
+ folderId: string | null,
+}
diff --git a/src/common/util/url.tsx b/src/common/util/url.tsx
index 59ecab2..3eec18c 100644
--- a/src/common/util/url.tsx
+++ b/src/common/util/url.tsx
@@ -22,10 +22,14 @@ export const commentListRequestToParameter = (commentListRequest: CommentListReq
export const postListMemberRequestToParameter = (postListMemberRequest: PostListMemberRequest) => {
let query = `?username=${postListMemberRequest.username}&page=${postListMemberRequest.page}&size=${postListMemberRequest.size}`;
- if (postListMemberRequest.folderId) {
- query += `&folderId=${postListMemberRequest.folderId}`;
+ if (!postListMemberRequest.folderIds) {
+ return query;
}
+ postListMemberRequest.folderIds.forEach((folderId: string) => {
+ query += `&folderIds=${folderId}`;
+ });
+
return query;
}
diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx
index 90317bd..13fea05 100644
--- a/src/components/common/Header.tsx
+++ b/src/components/common/Header.tsx
@@ -95,7 +95,7 @@ function Header() {
className="w-full block px-4 py-2 text-gray-700 hover:bg-gray-100">
게시글 작성
-
내 블로그
diff --git a/src/components/folder/FolderSelectBox.tsx b/src/components/folder/FolderSelectBox.tsx
index 6eafbc6..fb7cb8a 100644
--- a/src/components/folder/FolderSelectBox.tsx
+++ b/src/components/folder/FolderSelectBox.tsx
@@ -6,8 +6,8 @@ import {getFolderTitle} from "../../common/util/string.tsx";
function FolderSelectBox({folders, depth = 0, selectedFolder, targetFolder, setTargetFolder, center}: {
folders: FolderType[],
depth?: number,
- selectedFolder?: FolderType,
- targetFolder: FolderType,
+ selectedFolder?: FolderType | null,
+ targetFolder: FolderType | null,
setTargetFolder: (folder: FolderType) => void,
center?: boolean,
}) {
@@ -36,7 +36,7 @@ function FolderSelectBox({folders, depth = 0, selectedFolder, targetFolder, setT
void,
setFolderOpen: (open: boolean) => void,
}) {
diff --git a/src/components/post/TagCard.tsx b/src/components/post/TagCard.tsx
index 1902c5e..f0c2c60 100644
--- a/src/components/post/TagCard.tsx
+++ b/src/components/post/TagCard.tsx
@@ -1,11 +1,11 @@
import {TagResponse} from "../../common/types/post.tsx";
-function TagCard({tag, onClick}: { tag: TagResponse, onClick: (tagName: string) => void }) {
+function TagCard({tag, onClick}: { tag: TagResponse, onClick: () => void }) {
return (
);
diff --git a/src/pages/blog/BlogPage.tsx b/src/pages/blog/BlogPage.tsx
index aa4c984..ecb6345 100644
--- a/src/pages/blog/BlogPage.tsx
+++ b/src/pages/blog/BlogPage.tsx
@@ -115,6 +115,26 @@ function BlogPage() {
setSelectedTagList([...selectedTagList, selectTag]);
}
+ const handleSelectedFolder = (folder: FolderType) => {
+ setSelectedFolder(folder);
+ setPage(0);
+ }
+
+ const getSelectedFolders = (folder: FolderType | null) => {
+ if (!folder) {
+ return [];
+ }
+
+ const folderIds = [folder.id];
+
+ if (folder.subFolders.length > 0) {
+ folder.subFolders.forEach((subFolder: FolderType) => {
+ folderIds.push(...getSelectedFolders(subFolder));
+ });
+ }
+ return folderIds;
+ }
+
useEffect(() => {
// todo: 내 게시글 불러오기 api
console.log(page, setPageInfo.toString());
@@ -133,6 +153,8 @@ function BlogPage() {
useEffect(() => {
navigate(`/blog/${username}?folder=${selectedFolder?.id || ""}`);
+ setPage(-1);
+ setPage(0);
}, [selectedFolder]);
useEffect(() => {
@@ -157,19 +179,26 @@ function BlogPage() {
setMember(res.data);
})
.catch(error => alert(error.response.data.message));
+ }, [username]);
+
+ useEffect(() => {
+ if (username === undefined) {
+ return;
+ }
getMemberPosts({
username: username,
- folderId: null,
+ folderIds: getSelectedFolders(selectedFolder),
page: page,
size: pageInfo.size,
})
.then((res) => {
+ console.log(res.data.page);
setPosts(res.data.content);
setPageInfo(res.data.page);
})
.catch(error => error.response.data.message);
- }, [username, page]);
+ }, [page, selectedFolder, username]);
return (
@@ -202,7 +231,7 @@ function BlogPage() {
username={username}
profileUrl={member.profileUrl}
addTag={addTag}
- setSelectedFolder={setSelectedFolder}/>
+ setSelectedFolder={handleSelectedFolder}/>
@@ -218,7 +247,7 @@ function BlogPage() {
username={username}
profileUrl={member.profileUrl}
addTag={addTag}
- setSelectedFolder={setSelectedFolder}
+ setSelectedFolder={handleSelectedFolder}
bgColor={"bg-gray-50"}
side={true}/>
diff --git a/src/pages/post/PostPage.tsx b/src/pages/post/PostPage.tsx
index 063756e..db145ce 100644
--- a/src/pages/post/PostPage.tsx
+++ b/src/pages/post/PostPage.tsx
@@ -45,10 +45,6 @@ function PostPage() {
return;
}
- if (!confirm("댓글을 등록하시겠습니까?")) {
- return;
- }
-
if (parentCommentId !== null) {
parentCommentId = findParentCommentId(comments, parentCommentId);
}
@@ -83,10 +79,6 @@ function PostPage() {
return null;
}
const handleUpdateComment = (content: string, taggedUsername: string | null, originalComment: CommentType | null) => {
- if (!confirm("댓글을 수정하시겠습니까?")) {
- return;
- }
-
if (!originalComment) {
alert("업데이트 할 댓글이 존재하지 않습니다.");
return;
@@ -189,11 +181,15 @@ function PostPage() {
-
Home
-
{` > `}
-
폴더
-
{` > `}
-
{post.title}
+
+ Home
+
+ {post.folder &&
+
+
{` > `}
+
{post.folder.title}
+
}
@@ -211,7 +207,7 @@ function PostPage() {
{post.tags.map(tag =>
{
- navigate(`/search?word=${tag.name}&option=태그`)
+ navigate(`/search?keyword=${tag.name}&option=TAG&sort=createdAt&isDescending=true&tab=post`)
}}/>)}
diff --git a/src/pages/post/WritePage.tsx b/src/pages/post/WritePage.tsx
index 01066c7..1696b1b 100644
--- a/src/pages/post/WritePage.tsx
+++ b/src/pages/post/WritePage.tsx
@@ -40,7 +40,7 @@ function WritePage() {
});
const [showTag, setShowTag] = useState(false);
- const [targetFolder, setTargetFolder] = useState
({id: crypto.randomUUID(), title: "", subFolders: []});
+ const [targetFolder, setTargetFolder] = useState(null);
const [uploadCount, setUploadCount] = useState(0);
const [exitPage, setExitPage] = useState(false);
@@ -59,11 +59,22 @@ function WritePage() {
setPost({...post, tags: [...post.tags, post.inputTag], inputTag: ""});
}
+ const getFolderId = (targetFolder: FolderType) => {
+ if (!targetFolder || targetFolder.id === "empty") {
+ return null;
+ }
+
+ return targetFolder.id;
+ }
const handleSubmit = () => {
if (uploadCount > 0) {
alert("업로드 중인 이미지가 있습니다. 잠시만 기다려주세요.");
return;
}
+ if (!targetFolder) {
+ alert("폴더를 선택해주세요.");
+ return;
+ }
setLoading(true);
@@ -72,13 +83,14 @@ function WritePage() {
createPost({
title: post.title,
content: post.content,
+ folderId: getFolderId(targetFolder),
tagNames: post.tags,
urls: urls,
})
.then(() => {
alert("작성되었습니다.");
setExitPage(true);
- navigate(`/blog/${loginState.username}`);
+ navigate(`/blog/${loginState.username}?folder=`);
})
.catch((error) => alert(error.response.data.message))
.finally(() => setLoading(false));
@@ -89,8 +101,12 @@ function WritePage() {
alert("업로드 중인 이미지가 있습니다. 잠시만 기다려주세요.");
return;
}
-
+ if (!targetFolder) {
+ alert("폴더를 선택해주세요.");
+ return;
+ }
if (!id) return;
+
setLoading(true);
const urls: string[] = getImgUrls(post.content);
@@ -99,13 +115,14 @@ function WritePage() {
id: id,
title: post.title,
content: post.content,
+ folderId: getFolderId(targetFolder),
tagNames: post.tags,
urls: urls,
})
.then(() => {
alert("수정되었습니다.");
setExitPage(true);
- navigate(`/blog/${loginState.username}`);
+ navigate(`/blog/${loginState.username}?folder=`);
})
.catch((error) => alert(error.response.data.message))
.finally(() => setLoading(false));
@@ -119,7 +136,7 @@ function WritePage() {
deletePost(id)
.then(() => {
alert("삭제되었습니다.");
- navigate(`/blog/${loginState.username}`);
+ navigate(`/blog/${loginState.username}?folder=`);
})
.catch((error) => alert(error.response.data.message));
}
@@ -151,6 +168,11 @@ function WritePage() {
}, []);
const folderData: FolderType[] = [
+ {
+ id: "empty",
+ title: "폴더 없음",
+ subFolders: [],
+ },
{
id: crypto.randomUUID(),
title: faker.lorem.words(),
@@ -226,6 +248,11 @@ function WritePage() {
content: res.data.content,
tags: sortByName(res.data.tags.map((tag: TagResponse) => tag.name)),
});
+ setTargetFolder({
+ id: res.data.folder.id,
+ title: res.data.folder.title,
+ subFolders: [],
+ });
})
.catch((error) => alert(error.response.data.message));
diff --git a/src/pages/setting/FolderSettingPage.tsx b/src/pages/setting/FolderSettingPage.tsx
index 6f4fbb1..88baa9d 100644
--- a/src/pages/setting/FolderSettingPage.tsx
+++ b/src/pages/setting/FolderSettingPage.tsx
@@ -49,11 +49,7 @@ function FolderSettingPage() {
}
const [openMoveModal, setOpenMoveModal] = useState(false);
- const [selectedFolder, setSelectedFolder] = useState({
- id: crypto.randomUUID(),
- title: "",
- subFolders: [],
- });
+ const [selectedFolder, setSelectedFolder] = useState(null);
const [editFolderId, setEditFolderId] = useState("");
const [editFolderTitle, setEditFolderTitle] = useState("");
const [targetFolder, setTargetFolder] = useState({
@@ -65,11 +61,12 @@ function FolderSettingPage() {
const folderMoveTypes = ["폴더 위로 옮깁니다.", "폴더 아래로 옮깁니다.", "폴더 내부로 옮깁니다."];
const handleMoveFolder = () => {
- if (handleDisabled(folderMoveType)) {
+ if (handleDisabled(folderMoveType) || !selectedFolder) {
alert("활성화된 동작 중에서 선택해주세요.");
return;
}
+
if (folderMoveType === 2) {
setFolders(prevFolders => {
const deleteFolderList = getDeleteFolderList(prevFolders, selectedFolder.id);
@@ -85,6 +82,10 @@ function FolderSettingPage() {
setOpenMoveModal(false);
}
const getModalMoveFolderList = (folders: FolderType[]) => {
+ if (!selectedFolder) {
+ return [];
+ }
+
const targetIndex = folders.findIndex((folder) => folder.id === targetFolder.id);
if (targetIndex !== -1) {
@@ -99,6 +100,10 @@ function FolderSettingPage() {
});
}
const getAddFolderModalList = (folders: FolderType[]) => {
+ if (!selectedFolder) {
+ return [];
+ }
+
return folders.map((folder: FolderType): FolderType => {
if (folder.id === targetFolder.id) {
return {...folder, subFolders: [...folder.subFolders, selectedFolder]};
@@ -132,7 +137,7 @@ function FolderSettingPage() {
}
const handleDisabled = (moveType: number) => {
- if (targetFolder.title === "") {
+ if (targetFolder.title === "" || !selectedFolder) {
return true;
}
@@ -307,7 +312,9 @@ function FolderSettingPage() {
-
{selectedFolder.title} 폴더를
+
+ {selectedFolder?.title} 폴더를
+
state.loginSlice);
- const [inputSearch, setInputSearch] = useState("");
const [posts, setPosts] = useState([]);
const [page, setPage] = useState(0);
const [pageInfo, setPageInfo] = useState({number: 0, size: 10, totalElements: 0, totalPages: 0});
+ const [isFolderEdit, setIsFolderEdit] = useState(false);
+ const [postIds, setPostIds] = useState([]);
+ const [folders, setFolders] = useState([]);
+ const [targetFolder, setTargetFolder] = useState(null);
+
+ const handleIsFolderEdit = () => {
+ if (!isFolderEdit) {
+ setIsFolderEdit(true);
+ setPostIds([]);
+ setTargetFolder(null);
+ return;
+ }
+
+ if (postIds.length === 0) {
+ setIsFolderEdit(false);
+ return;
+ }
+
+ if (confirm("폴더 수정을 취소하시겠습니까?")) {
+ setIsFolderEdit(false);
+ return;
+ }
+ }
+
+ const handleClickCheckBox = (event: ChangeEvent) => {
+ const {name, checked} = event.target;
+
+ if (checked) {
+ setPostIds(prev => [...prev, name]);
+ } else {
+ setPostIds(prev => prev.filter(id => id !== name));
+ }
+ }
+ const handleCheckBox = (id: string) => {
+ return postIds.indexOf(id) > -1;
+ }
+
+ const getTargetFolderId = (targetFolder : FolderType | null) => {
+ if (!targetFolder || targetFolder.id === "empty") {
+ return null;
+ }
+
+ return targetFolder.id;
+ }
+ const submitPostFolderUpdate = () => {
+ if (!confirm("변경사항을 저장하시겠습니까?")) {
+ return;
+ }
+
+ updatePostFolder({
+ postIds: postIds,
+ folderId: getTargetFolderId(targetFolder),
+ })
+ .then(() => {
+ alert("폴더가 수정되었습니다.");
+ setIsFolderEdit(false);
+ })
+ .catch((error) => alert(error.response.data.message));
+ }
+
useEffect(() => {
if (!loginState.username) {
return;
@@ -26,7 +88,7 @@ function PostSettingPage() {
getMemberPosts({
username: loginState.username,
- folderId: null,
+ folderIds: [],
page: page,
size: pageInfo.size,
})
@@ -35,18 +97,91 @@ function PostSettingPage() {
setPageInfo(res.data.page);
})
.catch((error) => alert(error.response.data.message));
+
+ // todo: folders 데이터
+ const folderData: FolderType[] = [
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ ],
+ },
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ ]
+ },
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ ],
+ },
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ {
+ id: crypto.randomUUID(),
+ title: faker.lorem.words(),
+ subFolders: [],
+ },
+ ]
+ },
+ ];
+ setFolders(folderData);
+ setFolders(prev => [{
+ id: "empty",
+ title: "폴더 없음",
+ subFolders: [],
+ }, ...prev]);
}, [loginState, page]);
return (
-
-
게시글 관리
-
-
-
-
+
+
게시글 관리
+ {isFolderEdit &&
+
+
+
+
+
}
+ {!isFolderEdit &&
+
+
+
}
{posts.map((post: PostResponse) => (
@@ -56,10 +191,17 @@ function PostSettingPage() {
{post.title}
{fullDateToKorean(post.createdAt)}
-
-
-
+ {!isFolderEdit &&
+
+
+
}
+ {isFolderEdit &&
+
}
))}
{posts.length === 0 &&