Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions gitmon-client/src/app/[id]/[repo]/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -70,17 +71,20 @@ export default async function BlogPost({
<h1 className="mb-4 text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl">
{post.title}
</h1>
<div className="flex items-center justify-center gap-4 text-muted-foreground">
<div className="flex items-center gap-1">
<Calendar className="h-4 w-4" />
<time dateTime={post.createdAt || new Date().toISOString()}>
{post.createdAt ? formatDate(post.createdAt) : 'Unknown date'}
</time>
</div>
<div className="flex items-center gap-1">
<MessageSquare className="h-4 w-4" />
<span>{'3'} comments</span>
<div className="flex items-center justify-between gap-4 text-muted-foreground">
<div className="flex items-center gap-4">
<div className="flex items-center gap-1">
<Calendar className="h-4 w-4" />
<time dateTime={post.createdAt || new Date().toISOString()}>
{post.createdAt ? formatDate(post.createdAt) : 'Unknown date'}
</time>
</div>
<div className="flex items-center gap-1">
<MessageSquare className="h-4 w-4" />
<span>{'3'} comments</span>
</div>
</div>
<PostButtons id={replaceId(id)} repo={repo} slug={slug} />
</div>
</header>

Expand Down
108 changes: 108 additions & 0 deletions gitmon-client/src/app/[id]/[repo]/[slug]/update/UpdatePost.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 생성페이지와 동일 코드 반복이 좀 많아서,
저번에 말씀드렸던 방식으로 처리하면 좋을 것 같습니다.

그것은 바로 create-post/1 처럼 게시글 id가 있을 경우 편집 페이지로 가는 방식

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 그러면 url은 update-post로 유지하고 같은 컴포넌트를 바라보게 하는게 더 좋을라나요?

Original file line number Diff line number Diff line change
@@ -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<Post, 'id'>
}

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 (
<div className="p-4">
<PostForm onPostSaved={handleSavePost} post={post} />
</div>
)
}
42 changes: 42 additions & 0 deletions gitmon-client/src/app/[id]/[repo]/[slug]/update/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
해당 포스트를 찾을 수 없습니다. <br />
<Link href={`/@${replaceId(id)}/${repo}`} className="text-blue-500 hover:underline">
다른 포스트 보기
</Link>
</div>
)
}
const post = await fetchPost(data?.githubDownloadUrl)

return <UpdatePost token={token} post={post} />
}
36 changes: 36 additions & 0 deletions gitmon-client/src/components/Post/PostButtons.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex items-center gap-4">
<Button onClick={handleUpdate} variant="outline">
수정
</Button>
<Button onClick={handleDelete} variant="outline">
삭제
</Button>
</div>
)
}
8 changes: 5 additions & 3 deletions gitmon-client/src/components/Post/PostForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Post, 'id'>
}

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<HTMLTextAreaElement>(null)

Expand Down
Loading