Skip to content

Commit 4ce6e0e

Browse files
committed
fix(fe/community) : 댓글조회 시 userId 제대로 조회, 최신순 정렬
1 parent d9a557d commit 4ce6e0e

File tree

9 files changed

+510
-1630
lines changed

9 files changed

+510
-1630
lines changed

front/package-lock.json

Lines changed: 272 additions & 1582 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

front/src/app/community/page.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,36 @@ export default function HomePage() {
1010
<RepositoryList />
1111
</main>
1212
);
13-
}
13+
}
14+
15+
// "use client"
16+
17+
// import { useState } from "react"
18+
// import { CommentList } from "@/components/community/CommentList"
19+
// import { CommentForm } from "@/components/community/CommentForm"
20+
21+
// export default function CommunityPage() {
22+
// const [refreshKey, setRefreshKey] = useState(0)
23+
24+
// return (
25+
// <main className="max-w-2xl mx-auto py-10">
26+
// <h1 className="text-2xl font-bold mb-6">💬 댓글 테스트 페이지</h1>
27+
28+
// {/* ✅ 댓글 작성 폼을 위로 이동 */}
29+
// <section className="mb-8">
30+
// <h2 className="text-lg font-semibold mb-3">댓글 작성</h2>
31+
// <CommentForm
32+
// analysisResultId="1"
33+
// memberId={1} // 로그인 후 실제 유저 ID로 대체
34+
// onCommentAdded={() => setRefreshKey((k) => k + 1)} // 작성 후 목록 새로고침
35+
// />
36+
// </section>
37+
38+
// {/* ✅ 댓글 목록은 아래쪽에 표시 */}
39+
// <section className="border-t border-border pt-6">
40+
// <h2 className="text-lg font-semibold mb-3">댓글 목록</h2>
41+
// <CommentList key={refreshKey} analysisResultId="1" />
42+
// </section>
43+
// </main>
44+
// )
45+
// }

front/src/components/analysis/RepositoryPublicSection.tsx

Lines changed: 163 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,126 @@
1+
// "use client"
2+
3+
// import { useEffect, useState } from "react"
4+
// import { Card } from "@/components/ui/card"
5+
// import { Button } from "@/components/ui/Button"
6+
// import { Switch } from "@/components/ui/switch"
7+
// import { ShareButton } from "@/components/analysis/ShareButton"
8+
// import { Globe, Lock, MessageSquare } from "lucide-react"
9+
// import { useRepositoryPublic } from "@/hooks/analysis/useRepositoryPublic"
10+
// import { CommentSection } from "@/components/community/CommentSection"
11+
// import { analysisApi } from "@/lib/api/analysis"
12+
// import type { HistoryResponseDto } from "@/types/analysis"
13+
14+
// interface Props {
15+
// userId: number
16+
// repoId: number
17+
// initialPublic: boolean
18+
// }
19+
20+
// export function RepositoryPublicSection({ userId, repoId, initialPublic }: Props) {
21+
// const { isPublic, togglePublic } = useRepositoryPublic(initialPublic, userId, repoId)
22+
23+
// const [analysisResultId, setAnalysisResultId] = useState<number | null>(null)
24+
// const [loading, setLoading] = useState(true)
25+
26+
// useEffect(() => {
27+
// const loadAnalysisId = async () => {
28+
// try {
29+
// const historyResponse: HistoryResponseDto = await analysisApi.getRepositoryHistory(userId, repoId)
30+
// // ✅ 최신 분석 결과 ID 추출
31+
// if (historyResponse.analysisVersions && historyResponse.analysisVersions.length > 0) {
32+
// const latest = historyResponse.analysisVersions[0]
33+
// setAnalysisResultId(latest.analysisId)
34+
// } else {
35+
// console.warn("이 리포지토리에 분석 기록이 없습니다.")
36+
// }
37+
// } catch (err) {
38+
// console.error("❌ 분석 히스토리 조회 실패:", err)
39+
// } finally {
40+
// setLoading(false)
41+
// }
42+
// }
43+
44+
// loadAnalysisId()
45+
// }, [userId, repoId])
46+
47+
// return (
48+
// <>
49+
// {/* 🌐 공개 설정 */}
50+
// <Card className="mb-8 p-6">
51+
// <div className="flex items-center justify-between">
52+
// <div className="flex items-center gap-3">
53+
// {isPublic ? (
54+
// <Globe className="h-5 w-5 text-green-500" />
55+
// ) : (
56+
// <Lock className="h-5 w-5 text-muted-foreground" />
57+
// )}
58+
// <div>
59+
// <h3 className="font-semibold">리포지토리 공개 설정</h3>
60+
// <p className="text-sm text-muted-foreground">
61+
// {isPublic
62+
// ? "이 리포지토리의 분석 결과가 커뮤니티에 공개됩니다."
63+
// : "이 리포지토리의 분석 결과는 비공개 상태입니다."}
64+
// </p>
65+
// </div>
66+
// </div>
67+
68+
// <div className="flex items-center gap-2">
69+
// <span className="text-sm text-muted-foreground">{isPublic ? "공개" : "비공개"}</span>
70+
// <Switch checked={isPublic} onCheckedChange={togglePublic} />
71+
// </div>
72+
// </div>
73+
// </Card>
74+
75+
// {/* 💬 커뮤니티 섹션 */}
76+
// {isPublic ? (
77+
// <>
78+
// <Card className="p-6 mb-8">
79+
// <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
80+
// <div>
81+
// <h3 className="mb-1 font-semibold">커뮤니티 반응</h3>
82+
// <p className="text-sm text-muted-foreground">다른 개발자들과 소통하세요.</p>
83+
// </div>
84+
// <div className="flex gap-2">
85+
// <Button variant="outline" size="sm" className="gap-2 bg-transparent">
86+
// <MessageSquare className="h-4 w-4" />
87+
// 댓글 (n)
88+
// </Button>
89+
// <ShareButton />
90+
// </div>
91+
// </div>
92+
// </Card>
93+
94+
// {/* ✅ analysisResultId가 있을 때만 CommentSection 표시 */}
95+
// {loading ? (
96+
// <p className="text-muted-foreground text-sm">분석 데이터를 불러오는 중...</p>
97+
// ) : analysisResultId ? (
98+
// <CommentSection analysisResultId={analysisResultId} memberId={userId} />
99+
// ) : (
100+
// <p className="text-muted-foreground text-sm">아직 분석 기록이 없습니다.</p>
101+
// )}
102+
// </>
103+
// ) : (
104+
// <Card className="p-6 text-center text-muted-foreground">
105+
// 🔒 이 리포지토리는 현재 비공개 상태입니다.
106+
// </Card>
107+
// )}
108+
// </>
109+
// )
110+
// }
111+
1112
"use client"
2113

114+
import { useEffect, useState } from "react"
3115
import { Card } from "@/components/ui/card"
4-
import { Button } from "@/components/ui/Button"
116+
import { Button } from "@/components/ui/button" // ✅ 대소문자 수정
5117
import { Switch } from "@/components/ui/switch"
6118
import { ShareButton } from "@/components/analysis/ShareButton"
7-
import { Globe, Lock, MessageSquare, Share2, ThumbsUp } from "lucide-react"
119+
import { Globe, Lock, MessageSquare } from "lucide-react"
8120
import { useRepositoryPublic } from "@/hooks/analysis/useRepositoryPublic"
9-
import { useState } from "react"
121+
import { CommentSection } from "@/components/community/CommentSection"
122+
import { analysisApi } from "@/lib/api/analysis"
123+
import type { HistoryResponseDto } from "@/types/analysis"
10124

11125
interface Props {
12126
userId: number
@@ -16,13 +130,30 @@ interface Props {
16130

17131
export function RepositoryPublicSection({ userId, repoId, initialPublic }: Props) {
18132
const { isPublic, togglePublic } = useRepositoryPublic(initialPublic, userId, repoId)
19-
const [liked, setLiked] = useState(false)
20-
const [likeCount, setLikeCount] = useState(42)
21133

22-
const handleLike = () => {
23-
setLiked((prev) => !prev)
24-
setLikeCount((prev) => (liked ? prev - 1 : prev + 1))
25-
}
134+
const [analysisResultId, setAnalysisResultId] = useState<number | null>(null)
135+
const [loading, setLoading] = useState(true)
136+
137+
useEffect(() => {
138+
const loadAnalysisId = async () => {
139+
try {
140+
const historyResponse: HistoryResponseDto = await analysisApi.getRepositoryHistory(userId, repoId)
141+
// ✅ 최신 분석 결과 ID 추출
142+
if (Array.isArray(historyResponse.analysisVersions) && historyResponse.analysisVersions.length > 0) {
143+
const latest = historyResponse.analysisVersions[0]
144+
setAnalysisResultId(latest.analysisId)
145+
} else {
146+
console.warn("이 리포지토리에 분석 기록이 없습니다.")
147+
}
148+
} catch (err) {
149+
console.error("❌ 분석 히스토리 조회 실패:", err)
150+
} finally {
151+
setLoading(false)
152+
}
153+
}
154+
155+
loadAnalysisId()
156+
}, [userId, repoId])
26157

27158
return (
28159
<>
@@ -56,28 +187,40 @@ export function RepositoryPublicSection({ userId, repoId, initialPublic }: Props
56187
{isPublic ? (
57188
<>
58189
<Card className="p-6 mb-8">
59-
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
190+
{/* 헤더 영역 */}
191+
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between mb-4">
60192
<div>
61193
<h3 className="mb-1 font-semibold">커뮤니티 반응</h3>
62194
<p className="text-sm text-muted-foreground">다른 개발자들과 소통하세요.</p>
63195
</div>
64-
<div className="flex gap-2">
196+
{/*<div className="flex gap-2">
65197
<Button variant="outline" size="sm" className="gap-2 bg-transparent">
66198
<MessageSquare className="h-4 w-4" />
67199
댓글 (n)
68200
</Button>
69201
<ShareButton />
70-
</div>
202+
</div>*/}
71203
</div>
72-
</Card>
73204

74-
{/* ⚠️ TODO: 댓글 컴포넌트 연결 위치 */}
75-
{/*
76-
<CommentSection
77-
repoId={repoId}
78-
userId={userId}
79-
/>
80-
*/}
205+
{/* 본문 영역: 댓글 작성 → 댓글 목록 */}
206+
{loading ? (
207+
<p className="flex flex-col gap-6">분석 데이터를 불러오는 중...</p>
208+
) : analysisResultId ? (
209+
<div className="text-muted-foreground text-sm">
210+
{/* ✏️ 댓글 작성 폼 */}
211+
<CommentSection analysisResultId={analysisResultId} memberId={userId} />
212+
213+
{/* 💬 댓글 목록 */}
214+
<div className="border-t pt-6">
215+
{/* 댓글 목록이 CommentSection 안에서 렌더링되거나 별도 CommentList가 있다면 여기에 배치 */}
216+
{/* 예: <CommentList analysisResultId={analysisResultId} /> */}
217+
{/* CommentSection이 이미 작성+조회 포함한다면 그대로 둬도 됨 */}
218+
</div>
219+
</div>
220+
) : (
221+
<p className="text-muted-foreground text-sm">아직 분석 기록이 없습니다.</p>
222+
)}
223+
</Card>
81224
</>
82225
) : (
83226
<Card className="p-6 text-center text-muted-foreground">

front/src/components/community/CommentForm.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,33 @@ import { useState } from "react"
44
import { Button } from "@/components/ui/Button"
55
import { Textarea } from "@/components/ui/textarea"
66
import { postComment } from "@/lib/api/community"
7+
import { useAuth } from "@/hooks/auth/useAuth" // ✅ 로그인 유저 정보 가져오기
78

89
interface CommentFormProps {
9-
analysisResultId: string
10-
memberId: number
11-
onCommentAdded?: () => void // 작성 후 목록 새로고침용 콜백
10+
analysisResultId: number
11+
onCommentAdded?: () => void
1212
}
1313

14-
export function CommentForm({ analysisResultId, memberId, onCommentAdded }: CommentFormProps) {
14+
export function CommentForm({ analysisResultId, onCommentAdded }: CommentFormProps) {
15+
const { user } = useAuth() // ✅ 로그인한 사용자 정보
1516
const [content, setContent] = useState("")
1617
const [loading, setLoading] = useState(false)
1718
const [error, setError] = useState<string | null>(null)
1819

1920
const handleSubmit = async (e: React.FormEvent) => {
2021
e.preventDefault()
22+
if (!user) {
23+
setError("로그인이 필요합니다.")
24+
return
25+
}
2126
if (!content.trim()) return
2227

2328
try {
2429
setLoading(true)
2530
setError(null)
26-
27-
await postComment(analysisResultId, memberId, content)
28-
setContent("") // 작성 후 textarea 초기화
29-
if (onCommentAdded) onCommentAdded()
31+
await postComment(analysisResultId, user.id, content) // ✅ 로그인 유저 id 전달
32+
setContent("")
33+
onCommentAdded?.()
3034
} catch (err) {
3135
console.error(err)
3236
setError("댓글 작성 중 오류가 발생했습니다.")

front/src/components/community/CommentList.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { Card } from "@/components/ui/card"
55
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
66
import { fetchComments } from "@/lib/api/community"
77
import { Comment } from "@/types/community"
8-
import { formatDistanceToNow } from "date-fns/formatDistanceToNow"
9-
import {ko } from "date-fns/locale/ko"
8+
import { formatDistanceToNow } from "date-fns"
9+
import { ko } from "date-fns/locale"
1010

11-
export function CommentList({ analysisResultId }: { analysisResultId: string }) {
11+
export function CommentList({ analysisResultId }: { analysisResultId: number }) {
1212
const [comments, setComments] = useState<Comment[]>([])
1313
const [loading, setLoading] = useState(true)
1414

@@ -23,7 +23,6 @@ export function CommentList({ analysisResultId }: { analysisResultId: string })
2323
setLoading(false)
2424
}
2525
}
26-
2726
loadData()
2827
}, [analysisResultId])
2928

@@ -40,7 +39,6 @@ export function CommentList({ analysisResultId }: { analysisResultId: string })
4039

4140
return (
4241
<Card key={c.id} className="p-5 rounded-2xl shadow-sm flex flex-col gap-3">
43-
{/* Header */}
4442
<div className="flex justify-between">
4543
<div className="flex gap-3 items-center">
4644
<Avatar className="h-10 w-10">
@@ -49,13 +47,10 @@ export function CommentList({ analysisResultId }: { analysisResultId: string })
4947
</Avatar>
5048
<div>
5149
<p className="font-semibold">{`User #${c.memberId}`}</p>
52-
<p className="text-sm text-muted-foreground">{`user${c.memberId}@example.com`}</p>
5350
</div>
5451
</div>
5552
<span className="text-sm text-muted-foreground">{timeAgo}</span>
5653
</div>
57-
58-
{/* Content */}
5954
<p className="text-[15px] text-gray-800 leading-relaxed">{c.comment}</p>
6055
</Card>
6156
)

front/src/components/community/CommentSection.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,25 @@ import { useState } from "react"
44
import { CommentList } from "./CommentList"
55
import { CommentForm } from "./CommentForm"
66

7-
export function CommentSection({ analysisResultId }: { analysisResultId: string }) {
7+
interface CommentSectionProps {
8+
analysisResultId: number
9+
memberId: number
10+
}
11+
12+
export function CommentSection({ analysisResultId, memberId }: CommentSectionProps) {
813
const [refreshKey, setRefreshKey] = useState(0)
914

1015
return (
11-
<div>
12-
<CommentList key={refreshKey} analysisResultId={analysisResultId} />
16+
<div className="mt-6 space-y-6">
17+
{/* ✏️ 댓글 작성 폼 */}
1318
<CommentForm
1419
analysisResultId={analysisResultId}
15-
memberId={1} // 로그인 후 실제 사용자 ID로 교체
20+
memberId={memberId}
1621
onCommentAdded={() => setRefreshKey((k) => k + 1)}
1722
/>
23+
24+
{/* 💬 댓글 목록 */}
25+
<CommentList key={refreshKey} analysisResultId={analysisResultId} />
1826
</div>
1927
)
20-
}
28+
}

0 commit comments

Comments
 (0)