diff --git a/src/components/common/post/detail/PostDetailActions.tsx b/src/components/common/post/detail/PostDetailActions.tsx
new file mode 100644
index 0000000..d796fd7
--- /dev/null
+++ b/src/components/common/post/detail/PostDetailActions.tsx
@@ -0,0 +1,73 @@
+import { useCallback } from "react";
+import { usePostDelete } from "@/hooks/usePostDelete";
+
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+ Button,
+} from "@/components/ui";
+
+import type { Post } from "@/types/post.type";
+import type { User } from "@/types/user.type";
+
+interface Props {
+ post: Post;
+ user: User;
+}
+
+export default function PostDetailActions({ post, user }: Props) {
+ const { handleDelete } = usePostDelete();
+
+ const handleDeleteClick = useCallback(() => {
+ handleDelete(post.id);
+ }, [post.id]);
+
+ return (
+
+ {post?.author === user?.id && (
+
+
+
+
+
+
+
+
+
+ 해당 모집 게시글을 삭제하시겠습니까?
+
+
+ 삭제하시면 영구적으로 삭제되어 복구할 수 없습니다.
+
+
+
+ 닫기
+
+ 삭제
+
+
+
+
+
+ )}
+
+ );
+}
diff --git a/src/components/common/post/detail/PostDetailContent.tsx b/src/components/common/post/detail/PostDetailContent.tsx
new file mode 100644
index 0000000..925ba7e
--- /dev/null
+++ b/src/components/common/post/detail/PostDetailContent.tsx
@@ -0,0 +1,18 @@
+import { Editor } from "@/components/write";
+import type { Post } from "@/types/post.type";
+
+interface Props {
+ post: Post;
+}
+
+export default function PostDetailContent({ post }: Props) {
+ return (
+
+
+
+ {post?.content && }
+
+
+
+ );
+}
diff --git a/src/components/common/post/detail/PostDetailHeader.tsx b/src/components/common/post/detail/PostDetailHeader.tsx
new file mode 100644
index 0000000..67bc84c
--- /dev/null
+++ b/src/components/common/post/detail/PostDetailHeader.tsx
@@ -0,0 +1,26 @@
+import type { Post } from "@/types/post.type";
+import { Separator } from "@/components/ui";
+import dayjs from "dayjs";
+
+interface Props {
+ post: Post;
+}
+
+export default function PostDetailHeader({ post }: Props) {
+ return (
+
+ );
+}
diff --git a/src/components/common/post/detail/PostDetailMeta.tsx b/src/components/common/post/detail/PostDetailMeta.tsx
new file mode 100644
index 0000000..b68e09f
--- /dev/null
+++ b/src/components/common/post/detail/PostDetailMeta.tsx
@@ -0,0 +1,103 @@
+import type { Post } from "@/types/post.type";
+import { Badge } from "@/components/ui";
+
+interface Props {
+ post: Post;
+}
+
+export default function PostDetailMeta({ post }: Props) {
+ return (
+
+
+
+ {/* 모집 인원 */}
+
+
+ 모집 인원
+
+
+ {post?.members}
+
+
+
+ {/* 진행 방식 */}
+
+
+ 진행 방식
+
+
+ {post?.progress_method}
+
+
+
+ {/* 예상 기간 */}
+
+
+ 예상 기간
+
+
+ {post?.duration}
+
+
+
+ {/* 연락 수단 */}
+
+
+
+ {/* 모집 분야 */}
+
+
+
+ 모집 분야
+
+
+ {post?.position?.map((pos: string) => (
+
+ {pos}
+
+ ))}
+
+
+
+ {/* 기술 스택 */}
+
+
+ 기술 스택
+
+
+ {post?.tech_stack?.map((tech: string) => (
+
}.svg`})
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/hooks/usePostDelete.ts b/src/hooks/usePostDelete.ts
new file mode 100644
index 0000000..d438a76
--- /dev/null
+++ b/src/hooks/usePostDelete.ts
@@ -0,0 +1,30 @@
+import supabase from "@/lib/supabase";
+import { useCallback } from "react";
+import { useNavigate } from "react-router";
+import { toast } from "sonner";
+
+export const usePostDelete = () => {
+ const navigate = useNavigate();
+
+ const handleDelete = useCallback(async (id: number) => {
+ if (!id) {
+ toast.error("게시글 ID를 찾을 수 없습니다.");
+ return;
+ }
+ try {
+ const { error } = await supabase.from("post").delete().eq("id", id);
+
+ if (error) {
+ toast.error(error.message);
+ return;
+ }
+
+ toast.success("글을 삭제하였습니다.");
+ navigate("/");
+ } catch (error) {
+ console.log(error);
+ throw error;
+ }
+ }, []);
+ return { handleDelete };
+};
diff --git a/src/pages/post/[id]/detail.tsx b/src/pages/post/[id]/detail.tsx
index bbc288d..1a9ef57 100644
--- a/src/pages/post/[id]/detail.tsx
+++ b/src/pages/post/[id]/detail.tsx
@@ -1,33 +1,19 @@
-import supabase from "@/lib/supabase";
-
+import { useEffect } from "react";
+import { useParams } from "react-router";
import { useAuthStore } from "@/stores";
import { usePostDetail } from "@/hooks/usePostDetail";
-import { useEffect } from "react";
-import { useNavigate, useParams } from "react-router";
-import { Editor } from "@/components/write";
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogTrigger,
- Button,
- Separator,
- Spinner,
-} from "@/components/ui";
+import PostDetailHeader from "@/components/common/post/detail/PostDetailHeader";
+import PostDetailActions from "@/components/common/post/detail/PostDetailActions";
+import PostDetailMeta from "@/components/common/post/detail/PostDetailMeta";
+import PostDetailContent from "@/components/common/post/detail/PostDetailContent";
+
+import { Separator, Spinner } from "@/components/ui";
import { toast } from "sonner";
-import { Badge } from "@/components/ui";
-import dayjs from "dayjs";
export default function PostDetail() {
const { id } = useParams();
const user = useAuthStore((state) => state.user);
- const navigate = useNavigate();
const { post, isLoading, isError } = usePostDetail(id);
@@ -37,203 +23,31 @@ export default function PostDetail() {
}
}, [isError]);
- if (!post && !isLoading) {
+ if (isLoading) {
return (
- 게시글이 존재하지 않습니다.
+
);
}
- const handleDelete = async () => {
- try {
- const { error } = await supabase.from("post").delete().eq("id", id);
-
- if (error) {
- toast.error(error.message);
- return;
- }
- toast.success("글을 삭제하였습니다.");
- navigate("/");
- } catch (error) {
- console.log(error);
- throw error;
- }
- };
+ if (!post) {
+ return (
+
+ 게시글이 존재하지 않습니다.
+
+ );
+ }
return (
<>
- {isLoading ? (
-
-
-
- ) : (
- <>
- {/* 수정 및 삭제 버튼 */}
-
- {post?.author === user?.id && (
-
-
-
-
-
-
-
-
-
- 해당 모집 게시글을 삭제하시겠습니까?
-
-
- 삭제하시면 영구적으로 삭제되어 복구할 수 없습니다.
-
-
-
- 닫기
-
- 삭제
-
-
-
-
-
- )}
-
-
-
-
-
-
-
- {/* 모집 인원 */}
-
-
- 모집 인원
-
-
- {post?.members}
-
-
-
- {/* 진행 방식 */}
-
-
- 진행 방식
-
-
- {post?.progress_method}
-
-
-
- {/* 예상 기간 */}
-
-
- 예상 기간
-
-
- {post?.duration}
-
-
-
- {/* 연락 수단 */}
-
-
-
- {/* 모집 분야 */}
-
-
-
- 모집 분야
-
-
- {post?.position?.map((pos: string) => (
-
- {pos}
-
- ))}
-
-
-
- {/* 기술 스택 */}
-
-
- 기술 스택
-
-
- {post?.tech_stack?.map((tech: string) => (
-
}.svg`})
- ))}
-
-
-
-
-
+ {user && }
+
+
-
+
-
-
-
- {post?.content && }
-
-
-
- >
- )}
+
>
);
}