11// src/pages/PostDetail.jsx
2- import React , { useEffect , useState , useMemo , useRef } from "react" ;
2+ import React , { useEffect , useState , useMemo , useRef , useCallback } from "react" ;
33import { useParams , useNavigate } from "react-router-dom" ;
44import "./PostDetail.css" ;
55import config from "../../config" ;
6+ import { promptLogin } from "../../utils/auth" ;
7+
8+ const parseIntSafe = ( v ) => {
9+ const n = Number ( v ) ;
10+ return Number . isFinite ( n ) ? n : null ;
11+ } ;
12+
13+ const deriveCommentCount = ( resp , data ) => {
14+ try {
15+ const fromHeader = resp ?. headers ?. get ?. ( "X-Total-Count" ) ;
16+ const n = parseIntSafe ( fromHeader ) ;
17+ if ( n !== null ) return n ;
18+ } catch ( _ ) { }
19+
20+ if ( Array . isArray ( data ) ) return data . length ;
21+ if ( data && typeof data === "object" ) {
22+ if ( typeof data . totalElements === "number" ) return data . totalElements ;
23+ if ( typeof data . total === "number" ) return data . total ;
24+ if ( Array . isArray ( data . content ) ) return data . content . length ;
25+ }
26+ return 0 ;
27+ } ;
628
729export default function PostDetail ( ) {
830 const { id } = useParams ( ) ; // /community/post/:id
@@ -37,28 +59,6 @@ export default function PostDetail() {
3759 ? tokenRaw . startsWith ( "Bearer " ) ? tokenRaw : `Bearer ${ tokenRaw } `
3860 : null ;
3961
40- // ===== helpers =====
41- const parseIntSafe = ( v ) => {
42- const n = Number ( v ) ;
43- return Number . isFinite ( n ) ? n : null ;
44- } ;
45-
46- const deriveCommentCount = ( resp , data ) => {
47- try {
48- const fromHeader = resp ?. headers ?. get ?. ( "X-Total-Count" ) ;
49- const n = parseIntSafe ( fromHeader ) ;
50- if ( n !== null ) return n ;
51- } catch ( _ ) { }
52-
53- if ( Array . isArray ( data ) ) return data . length ;
54- if ( data && typeof data === "object" ) {
55- if ( typeof data . totalElements === "number" ) return data . totalElements ;
56- if ( typeof data . total === "number" ) return data . total ;
57- if ( Array . isArray ( data . content ) ) return data . content . length ;
58- }
59- return 0 ;
60- } ;
61-
6262 // 좋아요 수 및 내 상태 재조회
6363 const refreshLikeStatus = async ( ) => {
6464 try {
@@ -141,7 +141,7 @@ export default function PostDetail() {
141141 } , [ id , authHeader ] ) ; // ✅ navigate 제거
142142
143143 // 공통: 댓글 목록 다시 불러오기
144- const fetchComments = async ( ) => {
144+ const fetchComments = useCallback ( async ( ) => {
145145 try {
146146 setLoadingComments ( true ) ;
147147 const bust = Date . now ( ) ;
@@ -168,20 +168,19 @@ export default function PostDetail() {
168168 } finally {
169169 setLoadingComments ( false ) ;
170170 }
171- } ;
171+ } , [ authHeader , id ] ) ;
172172
173173 useEffect ( ( ) => {
174174 // authHeader가 있거나 없더라도 댓글은 로드 시도
175175 if ( ! id ) return ;
176176 fetchComments ( ) ;
177- } , [ id , authHeader ] ) ;
177+ } , [ id , authHeader , fetchComments ] ) ;
178178
179179
180180 // 좋아요 토글
181181 const handleToggleLike = async ( ) => {
182182 if ( ! authHeader ) {
183- alert ( "로그인이 필요합니다." ) ;
184- navigate ( "/login" ) ; // 로그인 페이지로 리다이렉트 (경로 가정)
183+ promptLogin ( ) ;
185184 return ;
186185 }
187186 if ( liking ) return ;
@@ -235,8 +234,7 @@ export default function PostDetail() {
235234 const handleCreateComment = async ( ) => {
236235 if ( ! newComment . trim ( ) ) return ;
237236 if ( ! authHeader ) {
238- alert ( "로그인이 필요합니다." ) ;
239- navigate ( "/login" ) ;
237+ promptLogin ( ) ;
240238 return ;
241239 }
242240
@@ -273,8 +271,7 @@ export default function PostDetail() {
273271 const handleCreateReply = async ( parentId ) => {
274272 if ( ! replyContent . trim ( ) ) return ;
275273 if ( ! authHeader ) {
276- alert ( "로그인이 필요합니다." ) ;
277- navigate ( "/login" ) ;
274+ promptLogin ( ) ;
278275 return ;
279276 }
280277
0 commit comments