diff --git a/gitmon-client/src/app/[id]/[repo]/[slug]/page.tsx b/gitmon-client/src/app/[id]/[repo]/[slug]/page.tsx
index 4dc6a9b..9a0f479 100644
--- a/gitmon-client/src/app/[id]/[repo]/[slug]/page.tsx
+++ b/gitmon-client/src/app/[id]/[repo]/[slug]/page.tsx
@@ -3,12 +3,13 @@ import Link from 'next/link'
import { ArrowLeft, Calendar, MessageSquare } from 'lucide-react'
import { formatDate, replaceId } from '@lib/utils'
import { Separator } from '@components/ui/separator'
-import { CommentSection } from './CommentSection'
+import { CommentSection } from '@components/Post/CommentSection'
import { fetchPost } from '@lib/github'
import MarkdownRenderer from '@components/MarkdownRenderer'
import { ShareButton } from '@components/ShareButton'
import { LikeButton } from '@components/LikeButton'
import { cookies } from 'next/headers'
+import { PostButtons } from '@components/Post/PostButtons'
export default async function BlogPost({
params,
@@ -70,17 +71,20 @@ export default async function BlogPost({
{post.title}
-
-
-
-
-
-
-
-
{'3'} comments
+
+
+
+
+
+
+
+
+ {'3'} comments
+
+
diff --git a/gitmon-client/src/app/[id]/[repo]/[slug]/update/UpdatePost.tsx b/gitmon-client/src/app/[id]/[repo]/[slug]/update/UpdatePost.tsx
new file mode 100644
index 0000000..96bf796
--- /dev/null
+++ b/gitmon-client/src/app/[id]/[repo]/[slug]/update/UpdatePost.tsx
@@ -0,0 +1,108 @@
+'use client'
+
+import { useState } from 'react'
+
+import { useMutation } from '@tanstack/react-query'
+import { useParams, useRouter } from 'next/navigation'
+import { toast } from 'sonner'
+
+import { PostForm } from '@components/Post'
+import matter from 'gray-matter'
+import { titleToSlug } from '@lib/utils'
+import { Post, PostMeta } from '@lib/types'
+
+interface UpdatePostProps {
+ token: string | null
+ post: Omit
+}
+
+export default function UpdatePost({ token, post }: UpdatePostProps) {
+ const router = useRouter()
+ const { slug } = useParams()
+ const [user, setUser] = useState<{ id: string; repo: string }>()
+
+ console.log(slug)
+
+ const { mutate } = useMutation({
+ // 해당 부분을 업데이트치는 API 호출로 변경해야 함
+ mutationFn: async ({ title, blob }: { title: string; blob: Blob }) => {
+ const body = new FormData()
+ const fileName = titleToSlug(title)
+ body.append('title', fileName)
+ body.append('content', blob, fileName)
+ body.append('id', slug as string)
+
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_DOMAIN}/api/v1/posting`, {
+ method: 'PUT',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ body,
+ })
+
+ if (!response.ok) {
+ toast('게시글 저장에 실패했습니다.')
+ throw new Error('게시글 저장 실패')
+ }
+ return response
+ },
+ onSuccess: async (res, {}) => {
+ const { data } = await res.json()
+
+ toast('게시글이 저장되었습니다.')
+ router.push(`/${user?.id}/${user?.repo}/${data.id}`)
+ },
+ })
+
+ const handleSavePost = async ({ title, content }: { title: string; content: string }) => {
+ const res = await fetch(`${process.env.NEXT_PUBLIC_API_DOMAIN}/api/v1/member`, {
+ method: 'GET',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ 'Content-Type': 'application/json',
+ },
+ })
+
+ if (!res.ok) {
+ toast('사용자 정보를 가져오는 데 실패했습니다.')
+ return
+ }
+
+ const { data } = await res.json()
+ setUser({ id: data.githubUsername, repo: data.repoName })
+
+ if (!data.githubUsername || !data.repoName) {
+ toast('레포지토리 정보가 없습니다. 먼저 레포지토리를 설정해주세요.')
+ return
+ }
+
+ if (!title) {
+ toast('게시글 제목을 입력해주세요.')
+ return
+ }
+
+ const metadata: PostMeta = {
+ title: title.trim(),
+ slug: titleToSlug(title),
+ repo: data.repoName,
+ excerpt: content.slice(0, 100),
+ coverImage: '',
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ pinned: false,
+ tags: [],
+ author: data.githubUsername,
+ }
+
+ const markdown = matter.stringify(content, metadata)
+ const blob = new Blob([markdown], { type: 'text/markdown' })
+
+ mutate({ title, blob })
+ }
+
+ return (
+
+ )
+}
diff --git a/gitmon-client/src/app/[id]/[repo]/[slug]/update/page.tsx b/gitmon-client/src/app/[id]/[repo]/[slug]/update/page.tsx
new file mode 100644
index 0000000..8553c42
--- /dev/null
+++ b/gitmon-client/src/app/[id]/[repo]/[slug]/update/page.tsx
@@ -0,0 +1,42 @@
+import Link from 'next/link'
+import { cookies } from 'next/headers'
+
+import UpdatePost from './UpdatePost'
+import { replaceId } from '@lib/utils'
+import { fetchPost } from '@lib/github'
+
+export default async function Page({
+ params,
+}: {
+ params: Promise<{ slug: string; id: string; repo: string }>
+}) {
+ const { id, repo, slug } = await params
+ const token = (await cookies()).get('github_token')?.value ?? null
+
+ const res = await fetch(
+ `${process.env.NEXT_PUBLIC_API_DOMAIN}/api/v1/posting/github/${replaceId(id)}/${slug}`,
+ {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`,
+ },
+ },
+ )
+
+ const { data } = await res.json()
+
+ if (!data?.githubDownloadUrl) {
+ return (
+
+ 해당 포스트를 찾을 수 없습니다.
+
+ 다른 포스트 보기
+
+
+ )
+ }
+ const post = await fetchPost(data?.githubDownloadUrl)
+
+ return
+}
diff --git a/gitmon-client/src/app/[id]/[repo]/[slug]/CommentSection.tsx b/gitmon-client/src/components/Post/CommentSection.tsx
similarity index 100%
rename from gitmon-client/src/app/[id]/[repo]/[slug]/CommentSection.tsx
rename to gitmon-client/src/components/Post/CommentSection.tsx
diff --git a/gitmon-client/src/components/Post/PostButtons.tsx b/gitmon-client/src/components/Post/PostButtons.tsx
new file mode 100644
index 0000000..09efab3
--- /dev/null
+++ b/gitmon-client/src/components/Post/PostButtons.tsx
@@ -0,0 +1,36 @@
+'use client'
+
+import { Button } from '@components/ui'
+import { useRouter } from 'next/navigation'
+import React from 'react'
+
+interface PostButtonsProps {
+ id: string
+ repo: string
+ slug: string
+}
+
+export const PostButtons = ({ id, repo, slug }: PostButtonsProps) => {
+ const router = useRouter()
+
+ const handleUpdate = () => {
+ router.push(`/@${id}/${repo}/${slug}/update`)
+ }
+
+ const handleDelete = () => {
+ const confirm = window.confirm('정말 삭제하시겠습니까?')
+ if (confirm) {
+ console.log('delete')
+ }
+ }
+ return (
+
+
+
+
+ )
+}
diff --git a/gitmon-client/src/components/Post/PostForm.tsx b/gitmon-client/src/components/Post/PostForm.tsx
index e2e3d69..758477b 100644
--- a/gitmon-client/src/components/Post/PostForm.tsx
+++ b/gitmon-client/src/components/Post/PostForm.tsx
@@ -26,15 +26,17 @@ import {
} from 'lucide-react'
import Link from 'next/link'
import { useParams } from 'next/navigation'
+import { Post } from '@lib/types'
interface PostFormProps {
onPostSaved: (post: { title: string; content: string }) => void
+ post?: Omit
}
-export function PostForm({ onPostSaved }: PostFormProps) {
+export function PostForm({ onPostSaved, post }: PostFormProps) {
const params = useParams()
- const [title, setTitle] = useState('')
- const [content, setContent] = useState('')
+ const [title, setTitle] = useState(post?.title || '')
+ const [content, setContent] = useState(post?.content || '')
const [showImageUploader, setShowImageUploader] = useState(false)
const textareaRef = useRef(null)