Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement comments delete feature #23

Draft
wants to merge 60 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
0ed723e
feat: add LeftSideBar component
Sep 29, 2024
db79550
feat: add RightCommentBar
Sep 29, 2024
7d787a8
chore: resolve ci issue
Sep 29, 2024
3f75b35
feat: add BlogCard
Sep 30, 2024
40d331b
refactor: remove useless style
dev-khs Sep 30, 2024
86bb2fc
feat: add Layout container
dev-khs Sep 30, 2024
b0f0f81
feat: add responsive layout style
dev-khs Sep 30, 2024
7048f49
feat: add window event listener
dev-khs Sep 30, 2024
cc3f6cc
refactor: improve responsive layout style
dev-khs Sep 30, 2024
250636d
refactor: improve responsive layout style
dev-khs Sep 30, 2024
764770f
feat: add new styles
dev-khs Oct 1, 2024
67a89b2
feat: add button component
dev-khs Oct 1, 2024
79c5987
refactor: modify blog-card style
dev-khs Oct 1, 2024
19a8935
Merge branch 'feat/blog-card' into feat/layout
dev-khs Oct 1, 2024
df361ff
Merge branch 'feat/layout' into feat/button-component
dev-khs Oct 1, 2024
b26f6ea
feat: add comment box component
dev-khs Oct 1, 2024
efd1f24
feat: add icon component
dev-khs Oct 1, 2024
b348388
feat: add new icons
dev-khs Oct 1, 2024
bd9347d
feat: add BlogPage
dev-khs Oct 1, 2024
ad8fa02
refactor: add home icon
dev-khs Oct 1, 2024
4c8d42d
refactor: modify blog-card style
dev-khs Oct 3, 2024
e724a47
feat: add MainPage and Typography component
dev-khs Oct 3, 2024
3ae2e5e
feat: add introduction
dev-khs Oct 3, 2024
3e38804
feat: add FavoritePage
dev-khs Oct 3, 2024
2ffada3
feat: add BlogList component
dev-khs Oct 3, 2024
738375d
feat: implement BlogDetailPage screen
dev-khs Oct 3, 2024
09783ec
feat: implement BlogDetail api routes
dev-khs Oct 3, 2024
65aa254
chore: modify mock data
dev-khs Oct 3, 2024
ed8877b
refactor: modify blog styles
dev-khs Oct 4, 2024
b55dba0
feat: add create icon
dev-khs Oct 4, 2024
7908b7c
feat: add BlogCreatePage screen
dev-khs Oct 4, 2024
c846cb4
feat: add MarkdownPreview
dev-khs Oct 5, 2024
9807793
feat: improve and rename markdown component
dev-khs Oct 5, 2024
750ee7f
feat: add Input component
dev-khs Oct 5, 2024
55e34ed
feat: add Textarea component
dev-khs Oct 5, 2024
e28bb40
feat: add Link tag
dev-khs Oct 5, 2024
7257dcc
feat: implement LoginForm
dev-khs Oct 5, 2024
438bb48
feat: add supabase settings
dev-khs Oct 5, 2024
9a0af5b
feat: add SessionProvider and add zustand package
dev-khs Oct 5, 2024
24a7e94
feat: implement logout feature
dev-khs Oct 5, 2024
103deda
refactor: apply image precessing based on login status
dev-khs Oct 5, 2024
1a1f1dd
refactor: add user info nickname
dev-khs Oct 5, 2024
91a786e
feat: resolve conflict
dev-khs Oct 9, 2024
040e20b
feat: implement blog features
dev-khs Oct 6, 2024
b81aa53
feat: implement fetch blog detail data
dev-khs Oct 6, 2024
2fa4068
feat: implement fetch imageUrl
dev-khs Oct 6, 2024
68eda6f
feat: resolve conflict
dev-khs Oct 9, 2024
daa79c9
feat: add createComment function
dev-khs Oct 9, 2024
a34d48e
feat: implement createComment
dev-khs Oct 9, 2024
4ec32ba
feat: add get comment features
dev-khs Oct 9, 2024
88657cc
feat: update comment ui style
dev-khs Oct 10, 2024
866a852
feat: implement get all comments data
dev-khs Oct 10, 2024
193f2d9
refactor: modify fetch blogs data and remove useless file
dev-khs Oct 10, 2024
ce7fe3b
refactor: resolve conflict issue
dev-khs Oct 12, 2024
11dc4c6
feat: implement comment delete UI
dev-khs Oct 13, 2024
0a017c6
feat: implement delete feature
dev-khs Oct 13, 2024
0383307
feat: improve update comment
dev-khs Oct 13, 2024
6aa6f8e
feat: improve update create comment
dev-khs Oct 13, 2024
efe39c4
fix: resolve sonarcloud issue
dev-khs Oct 14, 2024
ddf2d40
feat: add IconButton
dev-khs Oct 14, 2024
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@supabase/supabase-js": "^2.45.4",
"axios": "^1.7.7",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.35.2",
Expand Down
30 changes: 30 additions & 0 deletions src/app/api/Blog/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {NextResponse} from 'next/server'

import {createBrowserClient} from '@/supabase/client'

export async function GET() {
const supabase = createBrowserClient()

try {
const [
{data: postsData, error: postsError},
{data: commentsData, error: commentsError},
] = await Promise.all([
supabase.from('posts').select('*'),
supabase.from('comments').select('*'),
])

if (postsError || commentsError) {
return NextResponse.json(
{error: postsError?.message || commentsError?.message},
{status: 500},
)
}
return NextResponse.json({posts: postsData, comments: commentsData})
} catch (error) {
return NextResponse.json(
{error: 'Error fetching blog detail and comments'},
{status: 500},
)
}
}
27 changes: 15 additions & 12 deletions src/app/api/BlogDetail/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,33 @@ import {createBrowserClient} from '@/supabase/client'

export async function GET(req: NextRequest) {
const supabase = createBrowserClient()

const {searchParams} = new URL(req.url)

const blogId = searchParams.get('id')

if (!blogId) {
return NextResponse.json({error: 'Blog ID is required'}, {status: 400})
}

try {
const {data, error} = await supabase
.from('posts')
.select('*')
.eq('id', blogId)
.single()

if (error) {
return NextResponse.json({error: error.message}, {status: 500})
const [
{data: postData, error: postError},
{data: commentsData, error: commentsError},
] = await Promise.all([
supabase.from('posts').select('*').eq('id', blogId).single(),
supabase.from('comments').select('*').eq('post_id', blogId), // comments 테이블에서 post_id가 blogId인 것들을 가져옴
])

if (postError || commentsError) {
return NextResponse.json(
{error: postError?.message || commentsError?.message},
{status: 500},
)
}

return NextResponse.json(data)
return NextResponse.json({post: postData, comments: commentsData})
} catch (error) {
return NextResponse.json(
{error: 'Error fetching blog detail'},
{error: 'Error fetching blog detail and comments'},
{status: 500},
)
}
Expand Down
42 changes: 42 additions & 0 deletions src/app/api/createComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {createBrowserClient} from '@/supabase/client'

export async function createComment({
username,
userId,
blogId,
content,
role,
}: {
username: string
userId: string
blogId: string
content: string
role: string
}) {
const supabase = createBrowserClient()

try {
const {data, error} = await supabase
.from('comments')
.insert([
{
username: username,
user_id: userId,
post_id: blogId,
content,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_role: role,
},
])
.select('*')

if (error) {
return alert('권한이 없습니다.')
}
return data[0]
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
}
}
31 changes: 31 additions & 0 deletions src/app/api/deleteComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createBrowserClient } from "@/supabase/client"

export async function deleteComment({
userId,
commentId,
role,
}: {
userId: string
commentId: string
role?: string
}) {
const supabase = createBrowserClient()

try {
const query = role === 'admin'
? supabase.from('comments').delete().eq('id', commentId)
: supabase.from('comments').delete().eq('user_id', userId).eq('id', commentId)

const { data, error } = await query

if (error) {
alert('삭제 권한이 없습니다.')
return null
}

return data
} catch (error) {
console.error(error)
return null
}
}
17 changes: 0 additions & 17 deletions src/app/api/getBlog.ts

This file was deleted.

29 changes: 22 additions & 7 deletions src/components/CommentInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import {useState} from 'react'
import {useCallback, useState} from 'react'

import Icon from '@/components/Icon'
import Input from '@/components/Input'

const CommentInput = () => {
interface Props {
onClick: (content: string) => Promise<void>
}

const CommentInput = ({onClick}: Props) => {
const [commentValue, setCommentValue] = useState('')

const handleSubmit = useCallback(
async (event: React.FormEvent) => {
event.preventDefault()

await onClick(commentValue)
},
[commentValue, onClick],
)

return (
<div className="relative md:w-full md:mr-0">
<div className="group absolute top-3 left-4 text-0 w-5 h-5">
Expand All @@ -14,11 +27,13 @@ const CommentInput = () => {
iconName="search"
/>
</div>
<Input
value={commentValue}
onChange={e => setCommentValue(e.target.value)}
placeholder="댓글을 입력해주세요."
/>
<form onSubmit={handleSubmit}>
<Input
value={commentValue}
onChange={e => setCommentValue(e.target.value)}
placeholder="댓글을 입력해주세요."
/>
</form>
</div>
)
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const ICONS = {
'M14.707 5.293a1 1 0 0 0-1.414 1.414L17.586 11H4a1 1 0 1 0 0 2h13.586l-4.293 4.293a1 1 0 0 0 1.414 1.414l6-6a1 1 0 0 0 0-1.414l-6-6z',
create:
'M 12 2 C 6.4889941 2 2 6.4889982 2 12 C 2 17.511002 6.4889941 22 12 22 C 17.511006 22 22 17.511002 22 12 C 22 6.4889982 17.511006 2 12 2 z M 12 4 C 16.430126 4 20 7.5698765 20 12 C 20 16.430123 16.430126 20 12 20 C 7.5698737 20 4 16.430123 4 12 C 4 7.5698765 7.5698737 4 12 4 z M 11.984375 6.9863281 A 1.0001 1.0001 0 0 0 11 8 L 11 11 L 8 11 A 1.0001 1.0001 0 1 0 8 13 L 11 13 L 11 16 A 1.0001 1.0001 0 1 0 13 16 L 13 13 L 16 13 A 1.0001 1.0001 0 1 0 16 11 L 13 11 L 13 8 A 1.0001 1.0001 0 0 0 11.984375 6.9863281 z',
delete:
'M15 2.1a.9.9 0 0 1 .122 1.792L15 3.9H9a.9.9 0 0 1-.122-1.792L9 2.1h6zm6 3a.9.9 0 0 1 .122 1.792L21 6.9h-1.159l-.691 10.361-.045.567c-.095 1.043-.221 1.573-.523 2.102a3.9 3.9 0 0 1-1.688 1.579l-.224.101c-.332.137-.661.21-1.184.248l-.38.021-.451.013-1.147.008-3.616-.001-.51-.006-.434-.011-.37-.018-.316-.027c-.341-.038-.595-.097-.84-.189l-.21-.087-.107-.05a3.9 3.9 0 0 1-1.688-1.579l-.166-.325-.088-.223c-.054-.154-.098-.32-.135-.518l-.053-.321-.046-.38-.063-.708-.062-.878L4.158 6.9H3a.9.9 0 0 1-.122-1.792L3 5.1h18zm-2.963 1.8H5.962l.691 10.315.066.741.034.277.036.226.04.185.045.152.051.129.059.115a2.1 2.1 0 0 0 .909.85l.126.054.142.044.168.035.206.027.255.02.314.014.606.012.784.003 3.776-.003.583-.011.307-.013.252-.018.206-.024.089-.014.155-.034.132-.042.118-.051a2.1 2.1 0 0 0 .909-.85c.074-.13.131-.285.179-.511l.045-.252.04-.31.037-.378.082-1.129.637-9.559zM10 9.6a.9.9 0 0 1 .892.778l.008.122v5a.9.9 0 0 1-1.792.122L9.1 15.5v-5a.9.9 0 0 1 .9-.9zm4 0a.9.9 0 0 1 .892.778l.008.122v5a.9.9 0 0 1-1.792.122L13.1 15.5v-5a.9.9 0 0 1 .9-.9z',
}

export type IconName = keyof typeof ICONS
Expand Down
25 changes: 25 additions & 0 deletions src/components/IconButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Icon, {type IconName} from '@/components/Icon'

interface Props {
type?: 'submit' | 'reset' | 'button'
buttonClassName?: string
iconClassName?: string
iconName: IconName
onClick?: () => void
}

const IconButton = ({
iconName,
buttonClassName,
iconClassName,
onClick,
type = 'button',
}: Props) => {
return (
<button className={buttonClassName} onClick={onClick} type={type}>
<Icon iconName={iconName} className={iconClassName} />
</button>
)
}

export default IconButton
Loading
Loading