Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5e00cd0
refactor: shared/ui 컴포넌트 파일 분리
kutta97 May 1, 2025
3bbefad
refactor: entities 및 features 레이어로 각 slice 별 api 관련 함수를 분리한다
kutta97 May 4, 2025
0d08baf
refactor: 게시물 조회에 관한 상태를 get-posts slice 의 segment 로 분리
kutta97 May 5, 2025
5d5f6f6
refactor: highlightText 유틸함수 인자 옵셔널하게 변경
kutta97 May 5, 2025
5202c4b
refactor: 게시물 조회 테이블 ui 컴포넌트 분리
kutta97 May 5, 2025
8769a7c
refactor: 게시물 추가 다이얼로그 ui 컴포넌트 분리
kutta97 May 5, 2025
42591dd
refactor: 게시물 수정 다이얼로그 ui 컴포넌트 분리
kutta97 May 5, 2025
730e9e2
refactor: 게시물 검색 및 필터 컨트롤 ui 컴포넌트 분리
kutta97 May 5, 2025
dae229a
refactor: 게시물 페이지네이션 ui 컴포넌트 분리
kutta97 May 5, 2025
c6c712a
fix: API 엔드포인트 중복 코드 제거
kutta97 May 5, 2025
1d6cb73
refactor: 댓글 좋아요 수를 업데이트하는 entities 레이어의 api 함수 분리
kutta97 May 5, 2025
580f60f
refactor: 댓글 조회에 관한 상태를 get-comments slice 의 segment 로 분리
kutta97 May 5, 2025
e30601f
refactor: 댓글 리스트 조회 ui 컴포넌트 분리
kutta97 May 5, 2025
10abcee
refactor: 댓글 추가 다이얼로그 ui 컴포넌트 분리
kutta97 May 5, 2025
788afcd
refactor: 댓글 수정 다이얼로그 ui 컴포넌트 분리
kutta97 May 5, 2025
73e9652
refactor: 게시물 상세 조회 모달 ui 컴포넌트 분리
kutta97 May 5, 2025
79d3b92
refactor: 유저 정보 조회 모달 ui 컴포넌트 분리
kutta97 May 5, 2025
8db225e
refactor: 유저 정보 조회를 유저 정보 조회 모달에서 수행
kutta97 May 5, 2025
10dbea4
chore: tanstackQuery 의존성 추가
kutta97 May 5, 2025
836ed7f
feat: QueryClientProvider 추가
kutta97 May 5, 2025
0621982
feat: 태그 조회 및 선택 ui 를 tags 슬라이스로 분리
kutta97 May 5, 2025
3e2bba5
feat: 유저 정보 조회 쿼리 추가
kutta97 May 5, 2025
db45016
refactor: get-user 디렉토리 제거
kutta97 May 5, 2025
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 @@ -12,6 +12,7 @@
"coverage": "vitest run --coverage"
},
"dependencies": {
"@tanstack/react-query": "^5.75.2",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
Expand Down
20 changes: 19 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 18 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,28 @@ import { BrowserRouter as Router } from "react-router-dom"
import Header from "./widgets/ui/Header.tsx"
import Footer from "./widgets/ui/Footer.tsx"
import PostsManagerPage from "./pages/PostsManagerPage.tsx"
import { PostsProvider } from "./features/post/get-posts/context.tsx"
import { CommentsProvider } from "./features/comment/get-comments/context.tsx"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"

const App = () => {
const queryClient = new QueryClient()

return (
<Router>
<div className="flex flex-col min-h-screen">
<Header />
<main className="flex-grow container mx-auto px-4 py-8">
<PostsManagerPage />
</main>
<Footer />
</div>
<QueryClientProvider client={queryClient}>
<div className="flex flex-col min-h-screen">
<Header />
<main className="flex-grow container mx-auto px-4 py-8">
<PostsProvider>
<CommentsProvider>
<PostsManagerPage />
</CommentsProvider>
</PostsProvider>
</main>
<Footer />
</div>
</QueryClientProvider>
</Router>
)
}
Expand Down
24 changes: 24 additions & 0 deletions src/entities/comment/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import ApiClient from "../../shared/api/apiClient.ts"
import { Comment, Comments, NewComment } from "./model.ts"

export const createComment = (comment: NewComment) => {
return ApiClient.post<Comment, NewComment>("/comments/add", comment)
}

export const fetchComments = (postId: number) => {
return ApiClient.get<Comments>(`/comments/post/${postId}`)
}

export const updateComment = (comment: Comment) => {
return ApiClient.put<Comment, Pick<Comment, "body">>(`/comments/${comment.id}`, {
body: comment.body,
})
}

export const updateCommentLikes = (commentId: number, likes: number) => {
return ApiClient.patch<Comment, Pick<Comment, "likes">>(`/comments/${commentId}`, { likes })
}

export const deleteComment = (commentId: number) => {
return ApiClient.del(`/comments/${commentId}`)
}
26 changes: 26 additions & 0 deletions src/entities/comment/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
interface User {
id: number
username: string
fullName: string
}

export interface Comment {
id: number
postId: number
body: string
likes: number
user: User
}

export interface Comments {
comments: Comment[]
limit: number
skip: number
total: number
}

export interface NewComment {
userId: User["id"]
postId: Comment["postId"]
body: Comment["body"]
}
26 changes: 26 additions & 0 deletions src/entities/post/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import ApiClient from "../../shared/api/apiClient.ts"
import { Post, Posts, NewPost } from "./model.ts"

export const createPost = (post: NewPost) => {
return ApiClient.post<Post, NewPost>(`/posts/add`, post)
}

export const fetchPosts = (limit: number, skip: number) => {
return ApiClient.get<Posts>("/posts", { limit, skip })
}

export const updatePost = (post: Post) => {
return ApiClient.put<Post, Post>(`/posts/${post.id}`, post)
}

export const deletePost = (postId: number) => {
return ApiClient.del(`/posts/${postId}`)
}

export const searchPosts = (searchQuery: string) => {
return ApiClient.get<Posts>(`/posts/search`, { q: searchQuery })
}

export const searchPostsByTag = (tag: string) => {
return ApiClient.get<Posts>(`/posts/tag/${tag}`)
}
25 changes: 25 additions & 0 deletions src/entities/post/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface Post {
id: number
userId: number
title: string
body: string
tags: string[]
reactions: {
likes: number
dislikes: number
}
views: number
}

export interface Posts {
limit: number
posts: Post[]
skip: number
total: number
}

export interface NewPost {
userId: Post["userId"]
title: Post["title"]
body: Post["body"]
}
6 changes: 6 additions & 0 deletions src/entities/tag/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ApiClient from "../../shared/api/apiClient.ts"
import { Tag } from "./model.ts"

export const fetchTags = () => {
return ApiClient.get<Tag[]>("/posts/tags")
}
5 changes: 5 additions & 0 deletions src/entities/tag/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Tag {
name: string
slug: string
url: string
}
13 changes: 13 additions & 0 deletions src/entities/user/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ApiClient from "../../shared/api/apiClient.ts"
import { User, Users } from "./model.ts"

export const fetchUsers = () => {
return ApiClient.get<Users>("/users", {
limit: 0,
select: ["username", "image"].join(","),
})
}

export const fetchUser = (userId: number) => {
return ApiClient.get<User>(`/users/${userId}`)
}
78 changes: 78 additions & 0 deletions src/entities/user/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
interface Hair {
color: string
type: string
}

interface Coordinates {
lat: number
lng: number
}

interface Address {
address: string
city: string
state: string
stateCode: string
postalCode: string
coordinates: Coordinates
country: string
}

interface Bank {
cardExpire: string
cardNumber: string
cardType: string
currency: string
iban: string
}

interface Company {
department: string
name: string
title: string
address: Address
}

interface Crypto {
coin: string
wallet: string
network: string
}

export interface BaseUser {
id: number
username: string
image: string
}

export interface User extends BaseUser {
firstName: string
lastName: string
maidenName: string
age: number
gender: string
email: string
phone: string
password: string
birthDate: string
bloodGroup: string
height: number
weight: number
eyeColor: string
hair: Hair
ip: string
address: Address
macAddress: string
university: string
bank: Bank
company: Company
ein: string
ssn: string
userAgent: string
crypto: Crypto
role: string
}

export interface Users {
users: BaseUser[]
}
57 changes: 57 additions & 0 deletions src/features/comment/add-comment/ui/comment-add-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../../../../shared/ui/dialog/dialog.tsx"
import { Textarea } from "../../../../shared/ui/textarea/textarea.tsx"
import { Button } from "../../../../shared/ui/button/button.tsx"
import { useComments } from "../../get-comments/context.tsx"
import { NewComment } from "../../../../entities/comment/model.ts"
import { useState } from "react"

type CommentAddDialogProps = {
postId?: number | null
showAddCommentDialog: boolean
setShowAddCommentDialog: (showAddCommentDialog: boolean) => void
}

export const CommentAddDialog = ({
postId = null,
showAddCommentDialog,
setShowAddCommentDialog,
}: CommentAddDialogProps) => {
const { addComment } = useComments()

const [newComment, setNewComment] = useState<Omit<NewComment, "postId"> & { postId: number | null }>({
body: "",
postId,
userId: 1,
})

// 댓글 추가
const _addComment = async () => {
if (newComment.postId === null) return

try {
await addComment(newComment as NewComment)
setShowAddCommentDialog(false)
setNewComment({ body: "", postId: null, userId: 1 })
} catch (error) {
console.error("댓글 추가 오류:", error)
}
}

return (
<Dialog open={showAddCommentDialog} onOpenChange={setShowAddCommentDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>새 댓글 추가</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<Textarea
placeholder="댓글 내용"
value={newComment.body}
onChange={(e) => setNewComment({ ...newComment, body: e.target.value })}
/>
<Button onClick={_addComment}>댓글 추가</Button>
</div>
</DialogContent>
</Dialog>
)
}
Loading