Skip to content

[FE] SISC1-210 [FIX] : 게시글 작성 모달, 보드액션 부분 오류 수정#116

Merged
DongEun02 merged 12 commits intomainfrom
SISC1-210-FE
Nov 26, 2025
Merged

[FE] SISC1-210 [FIX] : 게시글 작성 모달, 보드액션 부분 오류 수정#116
DongEun02 merged 12 commits intomainfrom
SISC1-210-FE

Conversation

@cmmoon03
Copy link
Contributor

@cmmoon03 cmmoon03 commented Nov 17, 2025

1) 작업한 이슈번호

SISC1-210

2) 변경 요약 (What & Why)

  • 무엇을 변경했는지:
    BoardActions.module.css, Modal.jsx, Modal.module.css

  • 변경했는지(문제/목표):

  1. 깃 푸시를 하며 오류 수정
  2. 피그마의 디자인 업데이트 적용

3) 스크린샷/동영상 (UI 변경 시)

image image

4) 상세 변경사항 (전부 다)

  • 스타일: 띄어쓰기, 문구 수정, 모달 부분의 '게시글 작성' 버튼 튀어나온 것 수정, 보드 액션부분 좌측으로 밀려있던 오류 수정

Summary by CodeRabbit

  • 신규 기능

    • 드래그앤드롭 및 다중 파일 첨부, 첨부 파일 목록(이름·크기 표시 및 삭제) 기능이 추가되었습니다.
    • 게시물 상세에서 인라인 편집(제목·내용·첨부 파일 편집) 및 편집 저장/취소 흐름이 추가되었습니다.
  • 스타일

    • 모달과 상세 페이지가 토큰 기반 반응형 레이아웃으로 전환되어 크기·간격·타이포그래피가 유연해졌습니다.
    • 보드 액션 영역 중앙 정렬이 개선되었고, 게시물 카드에 클릭 가능한 커서 스타일이 적용되었습니다.
  • 문구

    • "파일추가" → "파일 추가", 버튼 "저장" → "게시글 작성"으로 변경되었습니다.
  • 네비게이션

    • 팀 기반 경로 컨텍스트가 반영되어 목록/상세 이동 및 삭제 후 이동 경로가 팀 정보에 맞게 동작합니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 17, 2025

Warning

Rate limit exceeded

@cmmoon03 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 914c1aa and b15ec99.

📒 Files selected for processing (3)
  • frontend/src/components/Board/PostItem.jsx (1 hunks)
  • frontend/src/components/Board/PostItem.module.css (1 hunks)
  • frontend/src/pages/PostDetail.jsx (6 hunks)

Walkthrough

Board UI와 라우팅에 팀 컨텍스트가 도입되고, Modal에 드래그·다중 파일 첨부 및 파일 리스트/삭제 UI가 추가되었습니다. Modal/CSS가 반응형 토큰 기반으로 재작성되었고, PostItem과 PostDetail은 팀 기반 경로 및 편집·첨부 흐름을 지원하도록 변경되었습니다.

Changes

Cohort / File(s) 변경 요약
Board 액션 스타일
frontend/src/components/Board/BoardActions.module.css
.boardActions width를 908px로 변경, padding-right: 20px 제거, 수평 중앙 정렬(margin-left/right: auto) 추가.
Modal 컴포넌트 — 파일첨부 UI 및 시그니처 변경
frontend/src/components/Board/Modal.jsx
selectedFiles, onFileChange, onRemoveFile props 추가. 드래그·드롭, 다중 파일 선택, 파일 리스트 렌더링 및 삭제 버튼, 제출 버튼 레이블 변경(저장 → 게시글 작성).
Modal 스타일링 대규모 리팩터
frontend/src/components/Board/Modal.module.css
고정 크기 제거, CSS 변수 및 clamp() 기반 반응형 규칙 도입. 내부 스크롤바 스타일링, 파일 리스트·삭제 버튼 등 신규 스타일 추가.
PostItem: 팀 기반 라우팅 반영
frontend/src/components/Board/PostItem.jsx, frontend/src/components/Board/PostItem.module.css
currentTeam prop 추가, 클릭 시 경로를 /board/{team}/{post.id}로 변경(팀 미존재 시 'all' 기본). .postCardcursor: pointer 추가.
Board 페이지: 팀 컨텍스트 및 파일 상태 관리 추가
frontend/src/pages/Board.jsx
useParamsteam 도입. selectedFiles 상태 및 handleFileChange/handleRemoveFile 추가. 새 포스트에 파일 메타데이터 포함. ModalPostItem에 관련 props 전달.
PostDetail: 편집·첨부 지원 및 경로 변경
frontend/src/pages/PostDetail.jsx, frontend/src/pages/PostDetail.module.css
useParamspostId·team 사용, 편집모드(isEdit) 및 편집용 상태(editTitle, editContent, editFiles, newFiles) 추가. 파일 추가/삭제/저장/취소 흐름 구현, 삭제 후 /board/${team}로 네비게이션. CSS에 첨부·편집 UI 스타일 추가.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as 사용자
  participant Modal as Modal 컴포넌트
  participant Board as Board 페이지 상태
  Note over User,Modal: 파일 첨부 흐름 (드래그/선택/삭제)
  User->>Modal: 파일 드래그/드롭 또는 파일 선택
  Modal->>Modal: handleDragOver / handleDrop 처리
  Modal->>Board: onFileChange(files)
  Board->>Board: setSelectedFiles(files)
  Board-->>Modal: selectedFiles prop 전달
  User->>Modal: 파일 삭제 클릭
  Modal->>Board: onRemoveFile(index)
  Board->>Board: selectedFiles에서 항목 제거
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • 주의할 파일/영역:
    • Modal.module.css의 CSS 변수·clamp 동작 및 스크롤바 스타일링.
    • Modal의 드래그앤드롭 이벤트 경계(이벤트 전파, 파일 타입/사이즈 검증 여부).
    • 라우팅 변경으로 인한 경로 구성 및 네비게이션 테스트(팀 파라미터 포함).
    • selectedFiles의 구조(메타데이터)가 저장·전송 로직과 호환되는지 확인.

Possibly related PRs

Suggested labels

FE

Suggested reviewers

  • gxuoo
  • DongEun02

Poem

"토끼가 깡충, 파일을 모아둬
모달은 드래그를 반갑게 맞고
팀 길 따라 포스트는 여행 가네
스타일은 반응형으로 살랑살랑
배포 전엔 테스트로 당근 한 조각 🐇"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 내용의 주요 부분을 반영하고 있습니다. 게시글 작성 모달과 보드액션 부분의 오류 수정이라는 핵심 변경 사항을 명확하게 나타내고 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 607a5ad and 14abcf4.

📒 Files selected for processing (3)
  • frontend/src/components/Board/BoardActions.module.css (2 hunks)
  • frontend/src/components/Board/Modal.jsx (2 hunks)
  • frontend/src/components/Board/Modal.module.css (2 hunks)
🔇 Additional comments (3)
frontend/src/components/Board/BoardActions.module.css (1)

24-24: 레이아웃 중앙 정렬 방식이 적절합니다.

고정 너비(908px)와 margin-left: auto, margin-right: auto를 사용하여 보드 액션 컨테이너를 수평으로 중앙 정렬하는 방식은 올바르게 구현되었습니다.

Also applies to: 31-32

frontend/src/components/Board/Modal.jsx (1)

37-37: UI 텍스트 개선이 적절합니다.

"파일 추가"에 공백을 추가하고 버튼 레이블을 "저장"에서 "게시글 작성"으로 변경한 것은 한국어 표기 규칙에 맞고 사용자에게 더 명확한 의미를 전달합니다.

Also applies to: 69-69

frontend/src/components/Board/Modal.module.css (1)

64-64: 폼 간격 및 버튼 스타일링이 잘 개선되었습니다.

폼에 margin-bottom: 27px를 추가하여 적절한 수직 간격을 확보했고, 저장 버튼의 배경색을 기본 테마 색상인 파란색(rgba(29, 128, 244, 1))으로 변경한 것은 일관된 디자인 시스템을 따릅니다. align-self: flex-endflex-shrink: 0를 사용한 정렬 방식도 flexbox 레이아웃에 적합합니다.

Also applies to: 245-245, 247-248

Copy link
Contributor

@gxuoo gxuoo left a comment

Choose a reason for hiding this comment

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

Image

제가 실행했을 때는, 게시글 작성 모달이 이렇게 나와요. 이유를 생각해보시고, 수정해보시는 걸 추천드립니다~! 추후에, 모바일(휴대폰, 패드)와 데스크탑 반응형도 구현해야하니 검색해보세요~!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
frontend/src/components/Board/Modal.module.css (2)

206-249: .select option 요소에 토큰 기반 폰트 크기를 적용하세요.

line 248.select option 규칙에서 font-size: 16px;이 하드코딩되어 있습니다. 파일 전체에서 토큰 기반 접근을 취하고 있으므로 일관성을 위해 var(--font-base)로 수정하는 것을 권장합니다.

 .select option {
   font-weight: 400;
-  font-size: 16px;
+  font-size: var(--font-base);
   color: rgba(23, 23, 23, 1);
   background: rgba(255, 255, 255, 1);
 }

28-29: max-width: 90vw 중복 검토를 요청합니다.

line 28width: clamp(320px, 90vw, 906px)는 이미 뷰포트 너비의 90%를 상한으로 제한합니다. line 29max-width: 90vw는 중복될 수 있습니다. 반응형 동작을 검증한 후 필요 없다면 제거할 수 있습니다.

모바일(320px), 태블릿(768px), 데스크톱(1200px+) 환경에서 모달 크기가 예상대로 작동하는지 확인해주세요. 불필요하다면 다음과 같이 제거할 수 있습니다:

  width: clamp(320px, 90vw, 906px);
- max-width: 90vw;
  max-height: 90vh;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54896b5 and 3d48607.

📒 Files selected for processing (1)
  • frontend/src/components/Board/Modal.module.css (6 hunks)
🔇 Additional comments (2)
frontend/src/components/Board/Modal.module.css (2)

15-38: 반응형 CSS 토큰 구현이 잘 적용되었습니다.

CSS 변수를 활용한 토큰 기반 설계가 일관되게 구현되어 있습니다. clamp()를 통한 유동적인 스케일링은 모바일부터 데스크톱까지 안정적인 반응형 동작을 보장합니다. 특히 패딩, 마진, 글꼴 크기가 모두 토큰으로 관리되어 유지보수성이 향상되었습니다.


253-274: 버튼 개선사항이 이전 리뷰 피드백을 잘 반영합니다.

호버 색상이 rgba(24, 102, 195, 1)로 수정되어 자연스러운 시각적 피드백을 제공합니다. 추가로 align-self: flex-endflex-shrink: 0을 통해 버튼이 의도한 위치에 고정되며, :active 상태 추가로 완전한 상호작용 경험을 제공합니다. PR 목표인 "돌출된 버튼" 문제 해결이 잘 구현되었습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
frontend/src/components/Board/PostItem.jsx (1)

14-22: 프로덕션 코드에 디버깅용 console.log 문 제거 필요

handleCardClick 함수 내부에 디버깅용 console.log 문이 여러 개 남아있습니다(16-19줄). 이는 브라우저 콘솔을 어지럽히고 불필요한 성능 오버헤드를 발생시킬 수 있습니다.

다음 diff를 적용하여 디버깅 코드를 제거하세요:

 const handleCardClick = () => {
   const team = currentTeam || 'all';
-  console.log('=== 게시글 클릭 ===');
-  console.log('post.id:', post.id);
-  console.log('team:', team);
-  console.log('이동할 URL:', `/board/${team}/${post.id}`);
-
   navigate(`/board/${team}/${post.id}`, { state: { post } });
 };
frontend/src/pages/PostDetail.jsx (2)

21-24: 프로덕션 코드에 디버깅용 console.log 문 제거 필요

컴포넌트 렌더링 시 실행되는 디버깅 로그가 남아있습니다. 브라우저 콘솔을 어지럽히므로 제거해야 합니다.

다음 diff를 적용하세요:

 const PostDetail = () => {
   const { postId, team } = useParams();
   const navigate = useNavigate();
   const location = useLocation();
   const [post, setPost] = useState(null);
   const [loading, setLoading] = useState(true);
-
-  console.log('=== PostDetail 렌더링 ===');
-  console.log('postId:', postId);
-  console.log('team:', team);
-  console.log('location.state:', location.state);
-

72-98: useEffect 내부의 디버깅 로그 제거 필요

게시글 로딩 로직은 올바르게 구현되었으나, 과도한 디버깅 로그(73, 77, 81-87, 95줄)가 남아있습니다.

다음 diff를 적용하여 디버깅 로그를 제거하세요:

   useEffect(() => {
-    console.log('=== useEffect 실행 ===');
     setLoading(true);
     let currentPost = location.state?.post;
-
-    console.log('currentPost from location.state:', currentPost);
-
     if (!currentPost) {
       const allPosts = getPostsFromStorage();
-      console.log('모든 게시글:', allPosts);
-      console.log('찾는 postId:', postId, 'type:', typeof postId);
-      currentPost = allPosts.find((p) => {
-        console.log('비교:', p.id, '===', parseInt(postId, 10));
-        return p.id === parseInt(postId, 10);
-      });
-      console.log('찾은 게시글:', currentPost);
+      currentPost = allPosts.find((p) => p.id === parseInt(postId, 10));
     }
     setPost(currentPost);
     setLoading(false);
 
     if (currentPost) {
       setComments(getCommentsFromStorage(currentPost.id));
     } else {
-      console.log('❌ 게시글을 찾을 수 없습니다!');
       setComments([]);
     }
   }, [postId, location.state]);
frontend/src/pages/Board.jsx (2)

10-12: 프로덕션 코드에 디버깅용 console.log 문 제거 필요

컴포넌트 렌더링 시마다 실행되는 디버깅 로그가 남아있습니다.

다음 diff를 적용하세요:

 const Board = () => {
   const { team } = useParams();
-  console.log('=== Board 렌더링 ===');
-  console.log('현재 team:', team);
-

180-191: PostItem 렌더링 시 디버깅 로그 제거 필요

PostItem 렌더링 시마다 console.log가 실행되어 성능에 영향을 줄 수 있습니다.

다음 diff를 적용하세요:

       {filteredPosts.length > 0 ? (
-        filteredPosts.map((post) => {
-          console.log('PostItem 렌더링, post.id:', post.id, 'team:', team);
-          return (
-            <PostItem
-              key={post.id}
-              post={post}
-              currentTeam={team}
-              onLike={handleLike}
-              onBookmark={handleBookmark}
-            />
-          );
-        })
+        filteredPosts.map((post) => (
+          <PostItem
+            key={post.id}
+            post={post}
+            currentTeam={team}
+            onLike={handleLike}
+            onBookmark={handleBookmark}
+          />
+        ))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0dcaafd and c5d35a2.

📒 Files selected for processing (6)
  • frontend/src/components/Board/Modal.jsx (4 hunks)
  • frontend/src/components/Board/Modal.module.css (6 hunks)
  • frontend/src/components/Board/PostItem.jsx (1 hunks)
  • frontend/src/pages/Board.jsx (6 hunks)
  • frontend/src/pages/PostDetail.jsx (3 hunks)
  • frontend/src/pages/PostDetail.module.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Board/Modal.jsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/components/Board/PostItem.jsx (1)
frontend/src/pages/PostDetail.jsx (2)
  • navigate (16-16)
  • post (18-18)
frontend/src/pages/Board.jsx (2)
frontend/src/pages/PostDetail.jsx (4)
  • useParams (15-15)
  • post (18-18)
  • handleLike (101-117)
  • handleBookmark (120-132)
frontend/src/components/Board/PostItem.jsx (1)
  • PostItem (11-78)
🔇 Additional comments (4)
frontend/src/pages/Board.jsx (1)

47-89: 파일 처리 로직이 잘 구현되었습니다

파일 이름과 크기를 기준으로 중복을 감지하고 교체하는 로직이 명확하게 구현되었습니다. 사용자에게 교체 알림을 제공하는 것도 좋은 UX입니다.

참고: 현재는 파일 메타데이터만 저장하고 실제 업로드는 구현되지 않았습니다. 향후 서버 연동 시 실제 파일 업로드 로직 추가가 필요합니다.

frontend/src/components/Board/Modal.module.css (3)

14-38: 반응형 CSS 토큰 시스템이 잘 설계되었습니다

CSS 커스텀 속성을 활용한 반응형 토큰 시스템(spacing, font, input-height, button-padding)이 일관되게 적용되었습니다. clamp() 함수를 사용하여 다양한 화면 크기에서 유연하게 대응할 수 있도록 구현되었습니다.

모달의 오버플로 처리도 overflow: hidden으로 변경되어 모서리가 잘 유지됩니다(37줄).


69-97: 스크롤 기능 및 스타일링이 적절하게 추가되었습니다

폼 컨테이너에 세로 스크롤(overflow-y: auto)을 추가하고, 커스텀 스크롤바 스타일을 적용하여 사용자 경험을 개선했습니다. 스크롤바 공간을 위한 padding-right: 8px 처리도 적절합니다.


171-206: 파일 첨부 UI가 적절하게 구현되었습니다

새로 추가된 파일 목록 UI 클래스들(.fileList, .fileItem, .fileName, .removeFileButton)이 Board.jsx 및 Modal.jsx의 파일 첨부 기능과 잘 연동됩니다.

특히 다음 사항들이 잘 구현되었습니다:

  • .fileNameword-break: break-all로 긴 파일명 처리(190줄)
  • .removeFileButtonflex-shrink: 0으로 버튼 크기 고정(201줄)
  • 호버 시 색상 변경으로 인터랙션 피드백 제공(204-206줄)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/Board.jsx (1)

41-45: 모달 닫을 때 selectedFiles 초기화 누락

handleCloseModal에서 titlecontent는 초기화하지만 selectedFiles는 초기화하지 않습니다. 사용자가 파일을 첨부한 후 저장하지 않고 모달을 닫으면, 다음 모달 오픈 시 이전 파일이 남아있게 됩니다.

  const handleCloseModal = () => {
    setShowModal(false);
    setTitle('');
    setContent('');
+   setSelectedFiles([]);
  };
🧹 Nitpick comments (3)
frontend/src/pages/Board.jsx (3)

10-12: 프로덕션 코드에서 console.log 제거 필요

디버그용 console.log 문은 프로덕션 배포 전에 제거해야 합니다. 불필요한 콘솔 출력은 성능에 영향을 주고 민감한 정보가 노출될 수 있습니다.

  const { team } = useParams();
-  console.log('=== Board 렌더링 ===');
-  console.log('현재 team:', team);
-

77-89: alert() 대신 비차단 알림 방식 고려

alert()는 UI를 차단하여 사용자 경험을 저해합니다. 토스트 메시지나 인라인 알림으로 대체하는 것이 좋습니다. 또한 디버그용 console.log도 제거가 필요합니다.

      // 교체된 파일이 있으면 알림
      if (replacedFileNames.length > 0) {
-       alert(`교체됨: ${replacedFileNames.join(', ')}`);
+       // TODO: 토스트 메시지로 대체 권장
+       console.info(`파일 교체됨: ${replacedFileNames.join(', ')}`);
      }

      return updatedFiles;
    });

    // input 초기화
    e.target.value = '';
-
-   console.log('파일 처리 완료');
  };

180-191: 렌더링 루프 내 console.log 제거 필요

map 콜백 내 console.log는 게시글 수에 비례하여 반복 실행되므로 성능에 영향을 줄 수 있습니다. 디버깅 완료 후 제거해 주세요.

          filteredPosts.map((post) => {
-           console.log('PostItem 렌더링, post.id:', post.id, 'team:', team);
-           return (
-             <PostItem
-               key={post.id}
-               post={post}
-               currentTeam={team}
-               onLike={handleLike}
-               onBookmark={handleBookmark}
-             />
-           );
-         })
+           <PostItem
+             key={post.id}
+             post={post}
+             currentTeam={team}
+             onLike={handleLike}
+             onBookmark={handleBookmark}
+           />
+         ))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5d35a2 and 2a45912.

📒 Files selected for processing (1)
  • frontend/src/pages/Board.jsx (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/Board.jsx (2)
frontend/src/pages/PostDetail.jsx (4)
  • useParams (15-15)
  • post (18-18)
  • handleLike (101-117)
  • handleBookmark (120-132)
frontend/src/components/Board/PostItem.jsx (1)
  • PostItem (11-78)
🔇 Additional comments (2)
frontend/src/pages/Board.jsx (2)

107-111: 파일 데이터 손실 가능성 확인 필요

현재 파일의 메타데이터(name, size, type)만 저장하고 있어, 실제 파일 내용은 localStorage에 저장되지 않습니다. 페이지 새로고침 후 첨부파일 다운로드나 표시가 불가능합니다.

의도된 동작인지, 아니면 향후 백엔드 연동 시 파일 업로드 로직 추가가 필요한지 확인해 주세요.


197-208: Modal 파일 첨부 통합 LGTM

파일 관련 props(selectedFiles, onFileChange, onRemoveFile)가 올바르게 전달되고 있으며, 이전 리뷰에서 지적된 handleSavedhandleSave 오류도 수정되었습니다.

Copy link
Contributor

@gxuoo gxuoo left a comment

Choose a reason for hiding this comment

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

리뷰 드렸어요 확인해보세요.

);
};

const handleSave = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

아래의 onSave 속성에 적용시키려고 만드신 것 같은데 정작 아래에는 handleSaved 라고 적으셨네요. 항상 개발하고 테스트 해보는 습관을 들여보세요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 수정하겠습니다.

const { team } = useParams();
console.log('=== Board 렌더링 ===');
console.log('현재 team:', team);

Copy link
Contributor

Choose a reason for hiding this comment

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

개발하면서 확인용으로 두신 거면, PR이 merge되기 전에 이러한 콘솔 로그는 모두 삭제해주시면 감사하겠습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

제가 정신이 없어서 제대로 확인을 못했습니다. 콘솔로그 전체 삭제했습니다.

const [selectedFiles, setSelectedFiles] = useState([]);

useEffect(() => {
localStorage.setItem('boardPosts', JSON.stringify(posts));
Copy link
Contributor

Choose a reason for hiding this comment

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

api 연결하면서 아마 로컬스토리지는 사용하지 않으셔도 될 거에요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

api 연결은 다른 브랜치에서 작업하고 있어서 기능 구현부터 하고서 연결하려고 했습니다.

// input 초기화
e.target.value = '';

console.log('파일 처리 완료');
Copy link
Contributor

Choose a reason for hiding this comment

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

이것도 PR merge 전에 삭제 부탁드려요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 수정하겠습니다.

e.stopPropagation();

const droppedFiles = Array.from(e.dataTransfer.files);
onFileChange({ target: { files: droppedFiles } });
Copy link
Contributor

Choose a reason for hiding this comment

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

onFileChange 라는 메서드가 정의되어 있지 않아요.. 확인 해보세요..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

onFileChange는 Modal의 props로 부모 컴포넌트(Board.jsx)로부터 전달받는 함수입니다. Board.jsx의 46번째 줄에서 handleFileChange로 정의되어 있고, 204번째 줄에서 Modal에 전달됩니다.

Comment on lines +16 to +19
console.log('=== 게시글 클릭 ===');
console.log('post.id:', post.id);
console.log('team:', team);
console.log('이동할 URL:', `/board/${team}/${post.id}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

이것도 merge 되기 전에 싹다 지워주세요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 수정했습니다.

Comment on lines 29 to 31
Copy link
Contributor

Choose a reason for hiding this comment

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

스타일 클래스를 만들어놓고 왜 style={{ cursor: 'pointer' }} 코드를 추가하신 거에요?

Copy link
Contributor

Choose a reason for hiding this comment

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

이 코드는 무슨 역할을 하는 거죠?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Files changed에서 해당 리뷰가 안 보여서 직접 작성합니다. 알림 여러번 가더라도 양해부탁드립니다. 디버깅할때 편하려고 추가했습니다.

Comment on lines +21 to +24
console.log('=== PostDetail 렌더링 ===');
console.log('postId:', postId);
console.log('team:', team);
console.log('location.state:', location.state);
Copy link
Contributor

Choose a reason for hiding this comment

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

참 많네요... 머지 되기 전에 지워주세요. 아래에 더 많은데 따로 코멘트 안 남길테니 알아서 지워주세요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵..

Copy link
Contributor

@DongEun02 DongEun02 left a comment

Choose a reason for hiding this comment

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

vsc 자체에서 알려주는 오류는 해결하고 PR 올려주세요. 그리고 AI 쓰는 건 상관없는데 AI 코드 그대로 올리지말고 자체적으로 수정해주세요. 이러면 나중에 더 힘들어집니다.

content,
setContent,
selectedFiles,
onFileChange,
Copy link
Contributor

Choose a reason for hiding this comment

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

props로 onFileChange를 받았는데 사용은 Modal 컴포넌트 바깥에서 하니까 정의되어 있지 않다고 나옵니다. 위치 옮겨주세요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 수정했습니다.

resize: none;
flex: 1;
font-family:
'Pretendard',
Copy link
Contributor

Choose a reason for hiding this comment

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

저번에 제가 index.css에서 font-family 지정해놔서 필요 없다고 리뷰 달았는데 또 해놓으셨네요. 지워주세요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이전에 삭제했다가 form 관련 요소 내부에는 폰트가 적용 안돼서 최근 추가했습니다.

- 인라인 편집 모드 구현
- 첨부파일 추가/삭제 기능
- 북마크 카운트 기능
- 코드 정리
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/Board.jsx (1)

39-43: 모달 닫을 때 selectedFiles 초기화 누락

handleCloseModal에서 titlecontent는 초기화하지만 selectedFiles는 초기화하지 않습니다. 모달을 닫았다가 다시 열면 이전에 선택한 파일이 그대로 남아있게 됩니다.

   const handleCloseModal = () => {
     setShowModal(false);
     setTitle('');
     setContent('');
+    setSelectedFiles([]);
   };
♻️ Duplicate comments (1)
frontend/src/components/Board/PostItem.jsx (1)

25-27: 인라인 스타일을 CSS 모듈로 이동 권장

style={{ cursor: 'pointer' }}가 인라인으로 적용되어 있습니다. 이전 리뷰에서도 지적된 부분으로, CSS 모듈에 정의하는 것이 일관성 있습니다.

🧹 Nitpick comments (3)
frontend/src/pages/PostDetail.jsx (3)

82-89: setLoading(false) 중복 호출

Line 82에서 이미 setLoading(false)를 호출했는데, Line 89에서 다시 호출하고 있습니다. 중복 호출을 제거하세요.

     setPost(currentPost);
     setLoading(false);

     if (currentPost) {
       setEditTitle(currentPost.title);
       setEditContent(currentPost.content);
     }

-    setLoading(false);
-
     if (currentPost) {

117-118: 중복 주석 제거 필요

// 북마크 토글 주석이 두 번 작성되어 있습니다. 과거 리뷰에서도 머지 전 정리 요청이 있었습니다.

-  // 북마크 토글
   // 북마크 토글
   const handleBookmark = () => {

360-382: 파일 목록 렌더링에서 index를 key로 사용

key={existing-${index}}key={new-${index}} 형태로 index를 key로 사용하고 있습니다. 파일 삭제 시 인덱스가 변경되어 리렌더링 이슈가 발생할 수 있습니다. 파일명 + 크기 조합 또는 고유 ID 사용을 권장합니다.

-                  <div
-                    key={`existing-${index}`}
+                  <div
+                    key={`existing-${file.name}-${file.size}`}

Also applies to: 386-411

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a45912 and 0ea0ba5.

📒 Files selected for processing (5)
  • frontend/src/components/Board/Modal.jsx (4 hunks)
  • frontend/src/components/Board/PostItem.jsx (1 hunks)
  • frontend/src/pages/Board.jsx (7 hunks)
  • frontend/src/pages/PostDetail.jsx (6 hunks)
  • frontend/src/pages/PostDetail.module.css (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/pages/PostDetail.module.css
🧰 Additional context used
🧬 Code graph analysis (3)
frontend/src/pages/PostDetail.jsx (2)
frontend/src/pages/Board.jsx (1)
  • useParams (10-10)
frontend/src/utils/TimeUtils.js (2)
  • getTimeAgo (1-26)
  • getTimeAgo (1-26)
frontend/src/components/Board/Modal.jsx (1)
frontend/src/pages/Board.jsx (1)
  • selectedFiles (29-29)
frontend/src/pages/Board.jsx (1)
frontend/src/pages/PostDetail.jsx (2)
  • useParams (16-16)
  • post (19-19)
🔇 Additional comments (11)
frontend/src/pages/PostDetail.jsx (2)

139-145: 수정 모드 진입 시 파일 상태 초기화 로직 확인

handleEdit에서 post.filesundefined일 경우 빈 배열로 처리하는 방어 코드가 있어 좋습니다.


172-206: 수정 저장 로직 구현 확인

제목/내용 유효성 검사와 기존 파일 + 새 파일 병합 로직이 잘 구현되어 있습니다. 저장 후 newFiles 초기화도 적절합니다.

frontend/src/components/Board/PostItem.jsx (2)

11-18: 팀 컨텍스트를 활용한 네비게이션 경로 구성 확인

currentTeam prop을 추가하고 기본값으로 'all'을 사용하는 것은 적절합니다. Board.jsx에서 team 파라미터를 전달받아 일관된 라우팅이 가능합니다.


76-76: displayName 설정 확인

React.memo로 감싼 컴포넌트에 displayName을 설정하여 React DevTools에서 디버깅이 용이합니다.

frontend/src/components/Board/Modal.jsx (3)

55-71: 파일 섹션에 드래그 앤 드롭 지원 추가 확인

onDragOveronDrop 이벤트 핸들러가 적절히 연결되어 있고, multiple 속성으로 다중 파일 선택도 지원합니다.


82-102: 첨부 파일 목록 UI 구현 확인

선택된 파일 목록을 표시하고 개별 삭제 기능을 제공합니다. selectedFiles && selectedFiles.length > 0 조건으로 null/undefined 케이스를 적절히 처리하고 있습니다.


107-108: 접근 권한 선택 기능 미완성

<select> 요소가 defaultValue만 설정되어 있고 onChange 핸들러가 없습니다. 현재는 UI만 존재하고 실제 기능이 구현되지 않은 상태입니다. 추후 구현 예정이라면 TODO 주석을 추가하는 것을 권장합니다.

frontend/src/pages/Board.jsx (4)

45-85: 파일 선택 핸들러 중복 처리 로직 확인

동일한 파일명에 대해 크기가 같으면 무시하고, 크기가 다르면 교체하는 로직이 잘 구현되어 있습니다. 사용자에게 교체된 파일을 알림으로 알려주는 UX도 적절합니다.


94-112: 새 게시글 생성 시 파일 데이터 포함 확인

selectedFiles에서 필요한 속성(name, size, type)만 추출하여 저장하는 것은 좋은 접근입니다. File 객체 전체를 localStorage에 저장하면 직렬화 문제가 발생할 수 있기 때문입니다.


128-142: 북마크 카운트 초기값 처리

post.bookmarkCount || 1|| 0 패턴으로 undefined 케이스를 처리하고 있습니다. 기존 데이터와의 호환성을 위한 방어 코드로 적절합니다.


183-190: PostItem에 currentTeam prop 전달 확인

team 파라미터를 currentTeam으로 전달하여 각 게시글 클릭 시 올바른 경로로 네비게이션됩니다.

Comment on lines +22 to +28
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();

const droppedFiles = Array.from(e.dataTransfer.files);
onFileChange({ target: { files: droppedFiles } });
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

드래그 앤 드롭 핸들러에서 가짜 이벤트 객체 생성

onFileChange{ target: { files: droppedFiles } } 형태의 객체를 전달하고 있습니다. 이 방식은 동작하지만, Board.jsxhandleFileChange에서 e.target.value = ''를 호출할 때 에러가 발생할 수 있습니다. 드롭된 파일의 경우 target.value가 존재하지 않기 때문입니다.

Board.jsxhandleFileChange에서 방어 코드 추가를 권장합니다:

// Board.jsx - handleFileChange 끝부분
if (e.target.value !== undefined) {
  e.target.value = '';
}
🤖 Prompt for AI Agents
In frontend/src/components/Board/Modal.jsx around lines 22–28, the synthetic
event passed to onFileChange lacks a target.value which causes an error when
Board.jsx's handleFileChange attempts to reset e.target.value; fix by either
including a value property on the fake event (so target has files and value) OR,
preferably, update Board.jsx's handleFileChange to defensively check that
e.target.value is defined before setting it (only clear it when present).

Comment on lines +83 to +85
// input 초기화
e.target.value = '';
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

드래그 앤 드롭 시 e.target.value 접근 오류 가능성

Modal.jsxhandleDrop에서 가짜 이벤트 객체를 생성하여 onFileChange를 호출합니다. 이때 e.target.valueundefined이므로 Line 84의 e.target.value = '' 할당이 문제를 일으킬 수 있습니다.

-    // input 초기화
-    e.target.value = '';
+    // input 초기화 (드래그 앤 드롭 시에는 target.value가 없을 수 있음)
+    if (e.target && e.target.value !== undefined) {
+      e.target.value = '';
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// input 초기화
e.target.value = '';
};
// input 초기화 (드래그 앤 드롭 시에는 target.value가 없을 수 있음)
if (e.target && e.target.value !== undefined) {
e.target.value = '';
}
};
🤖 Prompt for AI Agents
In frontend/src/pages/Board.jsx around lines 83 to 85, the code unconditionally
sets e.target.value = '' which will throw when handleDrop calls onFileChange
with a fake event lacking target; change the code to first check that e &&
e.target && typeof e.target.value !== 'undefined' before assigning, or prefer
clearing the file input via a ref (if used) instead of relying on the passed
event; update the assignment to only run when the target exists (or replace with
ref.current.value = ''), ensuring no error when a synthetic/no-target event is
passed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/pages/Board.jsx (1)

29-43: 모달 닫기 시 selectedFiles 가 초기화되지 않는 문제

지금은:

  • handleCloseModal에서 showModal, title, content만 초기화하고,
  • handleSave에서도 handleCloseModal만 호출하기 때문에,

이전에 선택해 둔 selectedFiles가 모달을 닫거나 저장한 뒤에도 그대로 남습니다.

그 결과:

  • 글 작성을 취소했다가 다시 열었을 때 이전에 선택한 파일이 그대로 보이고,
  • 사용자가 파일을 손보지 않고 저장하면, 원래 취소하려던 파일들이 다음 글에 그대로 첨부될 수 있습니다.

모달을 닫을 때 파일 선택도 함께 리셋되도록 하는 편이 자연스러워 보입니다.

아래처럼 handleCloseModal에서 selectedFiles도 같이 초기화하는 것을 제안드립니다.

-  const handleCloseModal = () => {
-    setShowModal(false);
-    setTitle('');
-    setContent('');
-  };
+  const handleCloseModal = () => {
+    setShowModal(false);
+    setTitle('');
+    setContent('');
+    setSelectedFiles([]);
+  };

이렇게 하면 저장/취소/닫기 모두 동일하게 상태를 정리할 수 있습니다.

Also applies to: 95-113

🧹 Nitpick comments (4)
frontend/src/components/Board/PostItem.module.css (1)

10-12: 카드 클릭 가능 UI 스타일 추가 적절

게시글 카드를 클릭형 인터랙션으로 쓰기 위한 cursor: pointer 추가가 명확해서 좋습니다. 필요하다면 hover 시 살짝 배경색/그림자 효과를 주면 사용자가 더 잘 인지할 수 있을 것 같습니다.

frontend/src/pages/Board.jsx (2)

29-93: 파일 선택/교체 로직 전반적으로 잘 구성됨

selectedFiles를 기준으로

  • 동일 이름 & 동일 크기 파일은 무시,
  • 동일 이름 & 다른 크기 파일은 교체 후 alert로 안내,
  • 나머지는 신규 추가,

하는 흐름이 직관적이고, setSelectedFiles를 함수형 업데이트로 사용한 점도 좋습니다.

e.target.value가 존재할 때만 초기화하도록 한 조건 분기 덕분에 드래그 앤 드롭 등에서 가짜 이벤트 객체를 넘기는 경우에도 에러 없이 동작할 여지가 커졌습니다. 다만 파일이 많아질 수 있는 서비스라면, 나중에는 alert 대신 모달/토스트 등으로 교체를 안내하는 UX 개선을 고려해 보셔도 좋겠습니다.


198-207: Modal에 파일 관련 props 전달 구조 확인 권장

ModalselectedFiles, onFileChange, onRemoveFile을 넘겨서 작성 모달 내부에서 파일 리스트/삭제/드래그 앤 드롭을 처리하도록 분리한 구조는 좋습니다.

다만 Modal 컴포넌트가 다른 페이지에서도 재사용되고 있다면, 새로 추가된 props들이 필수가 아니라 선택(props optional)으로 안전하게 처리되는지 한 번만 확인해 주세요. 그렇지 않다면 기존 사용처에서 빠뜨린 props 때문에 런타임 에러가 날 수 있습니다.

frontend/src/pages/PostDetail.jsx (1)

136-203: 게시글 수정 + 첨부파일 편집 플로우 전체적으로 좋고, 약간의 상태 업데이트 개선 여지

  • isEdit 플래그로 보기/수정 모드를 명확히 분리하고,
  • 수정 모드에서만
    • 기존 파일(editFiles),
    • 새 파일(newFiles)
      를 따로 관리한 뒤,
  • handleSaveEdit에서 두 리스트를 합쳐 files로 저장하는 구조가 명확하고 유지보수하기 좋아 보입니다.
  • 취소 시에는 post의 원본 값을 다시 editTitle, editContent에 넣어서 내용 편집이 잘 되돌려집니다.

몇 가지 작은 개선 제안입니다:

  1. 파일 관련 상태는 함수형 업데이트 사용 권장

handleAddNewFile, handleRemoveExistingFile, handleRemoveNewFile에서 기존 state를 바로 캡처해 쓰고 있는데, 이벤트가 연달아 발생하는 경우를 고려하면 함수형 업데이트가 더 안전합니다.

  const handleRemoveExistingFile = (index) => {
-   setEditFiles(editFiles.filter((_, i) => i !== index));
+   setEditFiles((prev) => prev.filter((_, i) => i !== index));
  };

  const handleAddNewFile = (e) => {
    const files = Array.from(e.target.files);
-   setNewFiles([...newFiles, ...files]);
+   setNewFiles((prev) => [...prev, ...files]);
    e.target.value = '';
  };

  const handleRemoveNewFile = (index) => {
-   setNewFiles(newFiles.filter((_, i) => i !== index));
+   setNewFiles((prev) => prev.filter((_, i) => i !== index));
  };
  1. DOM 접근은 가능하면 ref로 감싸기

document.getElementById('editFileUpload').click() 대신 useRef로 input을 참조하면, 컴포넌트 리팩터링/ID 변경 시에도 더 안전합니다. (필수는 아니지만 장기적으로는 ref 기반이 관리에 유리합니다.)

전반적으로 기능은 잘 동작할 것으로 보이고, 위 개선은 추후 리팩터링 시 고려해 보시면 좋겠습니다.

Also applies to: 343-449

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ea0ba5 and a85e6a8.

📒 Files selected for processing (3)
  • frontend/src/components/Board/PostItem.module.css (1 hunks)
  • frontend/src/pages/Board.jsx (7 hunks)
  • frontend/src/pages/PostDetail.jsx (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/pages/Board.jsx (1)
frontend/src/pages/PostDetail.jsx (3)
  • useParams (16-16)
  • newFiles (26-26)
  • post (19-19)
🔇 Additional comments (6)
frontend/src/pages/Board.jsx (2)

7-11: URL 기반 team 정보를 PostItem으로 전달하는 구조 적절

useParams로 가져온 team을 그대로 PostItemcurrentTeam으로 넘겨서 카드 클릭 시 팀별 상세 경로로 이동하도록 한 흐름이 자연스럽습니다. 라우터 설정에 따라 /board/:team 외에 /board 단독 경로에서도 이 컴포넌트를 쓰고 있다면, 그 경우에도 PostItem 내부의 기본값 처리('all' 등)와 일관되게 동작하는지만 실제 화면에서 한 번만 확인해 보시면 좋겠습니다.

Also applies to: 185-189


103-110: 북마크 카운트 처리 로직 일관성 좋음

북마크 토글 시

  • isBookmarked를 반전시키고,
  • bookmarkCount|| 연산자를 사용해 undefined인 예전 데이터도 안전하게 처리하는 방식

으로 구현하신 부분이 좋아 보입니다. 특히 (post.bookmarkCount || 1) - 1 / (post.bookmarkCount || 0) + 1 패턴 덕분에 과거에 bookmarkCount 필드가 없던 게시글도 자연스럽게 0↔1로 왕복되겠습니다.

Also applies to: 129-139

frontend/src/pages/PostDetail.jsx (4)

16-27: 라우트 기반 로딩 + 편집 초기화 플로우가 자연스러움

useParams에서 postId, team을 받고,

  • location.state?.post가 있으면 그대로 사용,
  • 없으면 localStorage에서 postId로 찾아오는 fallback,
  • 찾은 후에는 곧바로 editTitle, editContent를 초기화,

하는 흐름이 상세 페이지 진입 시 UX와 데이터 동기화 면에서 잘 설계된 것 같습니다. currentPost가 없을 때는 댓글도 빈 배열로 초기화해 주어 에러 케이스도 무난히 처리되고 있습니다.

Also applies to: 73-95


115-134: 상세 페이지에서도 북마크/좋아요 카운트 일관성 유지

상세 페이지에서:

  • handleBookmarkisBookmarked 토글 + bookmarkCount 증감(초기 undefined 안전 처리 포함),
  • handleLikeisLiked 토글 + likeCount 증감,

을 처리하고, 하단 댓글 섹션의 액션 버튼에서 동일한 값을 렌더링하는 구조가 Board 목록과 잘 맞습니다.

bookmarkCount > 0일 때만 숫자를 보여주는 조건도 자연스럽고, 로직과 UI 간의 일관성이 좋아 보입니다.

Also applies to: 464-495


205-213: 게시글 삭제 후 이동 경로 수정이 팀 컨텍스트와 잘 맞음

삭제 시 navigate(/board/${team || 'all'})로 이동하도록 바꾸신 부분이:

  • team이 있는 경우: 해당 팀 게시판으로,
  • 없는 경우: /board/all로,

일관되게 보내 주어, 앞서 Board/PostItem 쪽에서 사용 중인 기본값 전략과도 잘 맞는 것 같습니다.


278-451: 편집 모드와 댓글 섹션의 모드 분리가 명확함

  • 제목/내용/첨부파일은 isEdit에 따라 입력 컴포넌트 ↔ 정적 텍스트로 잘 토글되고,
  • 첨부파일 영역도
    • 수정 모드: 기존/새 파일 리스트 + 삭제 버튼 + 파일 추가 버튼,
    • 일반 모드: 파일이 있을 때만 목록 표시,
      로 분리되어 있어 사용자가 현재 상태를 이해하기 쉽습니다.
  • 수정 모드일 때 댓글 작성/목록 UI 전체를 숨기고, 수정 완료/취소 버튼만 보여주는 점도 UX 상 자연스럽습니다.

렌더링 조건과 상태 플래그가 깔끔하게 맞물려 있어서 유지보수하기에도 괜찮은 구조로 보입니다.

Also applies to: 464-571

Comment on lines +278 to 320
{isEdit ? (
<input
className={styles.editTitleInput}
type="text"
value={editTitle}
onChange={(e) => setEditTitle(e.target.value)}
placeholder="제목을 입력하세요"
/>
) : (
<h1 className={styles.title}>{post.title}</h1>
)}

{!isEdit && (
<div className={styles.menuContainer}>
<button
className={styles.menuButton}
onClick={() => setShowMenu(!showMenu)}
>
</button>
{showMenu && (
<div className={styles.menuDropdown}>
<button onClick={handleEdit}>
<img
src={EditIcon}
className={styles.EditIcon}
alt="수정"
/>
수정하기
</button>
<button onClick={handleDelete}>
<img
src={DeleteIcon}
className={styles.DeleteIcon}
alt="삭제"
/>
삭제하기
</button>
</div>
)}
</div>
)}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

상단 ⋮ 메뉴 버튼의 접근성 속성 보완 제안

상단 제목 우측의 ⋮ 메뉴 버튼은 시각적으로는 명확하지만, 하단 댓글 메뉴 버튼과 달리 aria-label이 없습니다. 스크린리더 사용자를 위해 어떤 메뉴인지 설명이 필요해 보입니다.

예를 들어:

-              <button
-                className={styles.menuButton}
-                onClick={() => setShowMenu(!showMenu)}
-              >
+              <button
+                className={styles.menuButton}
+                onClick={() => setShowMenu(!showMenu)}
+                aria-label="게시글 메뉴 열기"
+              >
                 ⋮
               </button>

와 같이 보완해 두면 좋겠습니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{isEdit ? (
<input
className={styles.editTitleInput}
type="text"
value={editTitle}
onChange={(e) => setEditTitle(e.target.value)}
placeholder="제목을 입력하세요"
/>
) : (
<h1 className={styles.title}>{post.title}</h1>
)}
{!isEdit && (
<div className={styles.menuContainer}>
<button
className={styles.menuButton}
onClick={() => setShowMenu(!showMenu)}
>
</button>
{showMenu && (
<div className={styles.menuDropdown}>
<button onClick={handleEdit}>
<img
src={EditIcon}
className={styles.EditIcon}
alt="수정"
/>
수정하기
</button>
<button onClick={handleDelete}>
<img
src={DeleteIcon}
className={styles.DeleteIcon}
alt="삭제"
/>
삭제하기
</button>
</div>
)}
</div>
)}
</div>
{isEdit ? (
<input
className={styles.editTitleInput}
type="text"
value={editTitle}
onChange={(e) => setEditTitle(e.target.value)}
placeholder="제목을 입력하세요"
/>
) : (
<h1 className={styles.title}>{post.title}</h1>
)}
{!isEdit && (
<div className={styles.menuContainer}>
<button
className={styles.menuButton}
onClick={() => setShowMenu(!showMenu)}
aria-label="게시글 메뉴 열기"
>
</button>
{showMenu && (
<div className={styles.menuDropdown}>
<button onClick={handleEdit}>
<img
src={EditIcon}
className={styles.EditIcon}
alt="수정"
/>
수정하기
</button>
<button onClick={handleDelete}>
<img
src={DeleteIcon}
className={styles.DeleteIcon}
alt="삭제"
/>
삭제하기
</button>
</div>
)}
</div>
)}
</div>
🤖 Prompt for AI Agents
In frontend/src/pages/PostDetail.jsx around lines 278 to 320, the top-right "⋮"
menu button lacks accessibility attributes for screen readers; add an
appropriate aria-label (e.g., "게시물 옵션 메뉴" or "More options") to the button, and
also include aria-haspopup="true" and aria-expanded={showMenu} to convey that it
controls a popup menu and whether it is open; ensure the label is localized if
your app supports multiple languages.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a85e6a8 and 914c1aa.

📒 Files selected for processing (1)
  • frontend/src/components/Board/PostItem.jsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Board/PostItem.jsx (1)
frontend/src/pages/PostDetail.jsx (2)
  • navigate (17-17)
  • post (19-19)
🔇 Additional comments (2)
frontend/src/components/Board/PostItem.jsx (2)

11-11: 구현이 올바르게 완료되었습니다 - 추가 조치 불필요

검증 결과, currentTeam prop이 Board.jsx에서 올바르게 전달되고 있으며, 라우팅도 /board/:team/:postId 패턴에 맞게 정상 구성되어 있습니다. PostDetail.jsx도 새로운 라우트 파라미터를 올바르게 처리하고 있습니다.

  • ✅ Board.jsx에서 currentTeam={team} 올바르게 전달
  • ✅ PostItem의 네비게이션 경로 정확함: /board/${team}/${post.id}
  • ✅ App.jsx 라우트 설정 완료: /board/:team, /board/:team/:postId
  • ✅ PostDetail에서 team, postId 파라미터 정확히 추출

PropTypes 추가는 선택적 개선사항으로 진행하셔도 되고 생략하셔도 무방합니다.


14-18: 라우트 설정 검증 완료 - 구현이 올바릅니다

라우터 설정 검증 결과, 변경사항이 완벽하게 구현되었습니다:

  • ✓ App.jsx line 31에 /board/:team/:postId 라우트 정의됨
  • ✓ PostDetail.jsx line 16에서 useParams()teampostId 모두 추출
  • ✓ PostItem.jsx의 네비게이션 경로가 라우트 정의와 일치
  • currentTeam || 'all' 폴백 로직 적절함

breaking change는 완전히 구현되었으며 추가 작업이 필요하지 않습니다.

Copy link
Contributor

@gxuoo gxuoo left a comment

Choose a reason for hiding this comment

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

레이아웃이나 다른 디자인 요소들은 나중에 한 번에 다 바꾸는 게 좋을 거 같아서 일부로 말씀 안 드렸어요. 기능만 잘 돌아가게 해주세요. 고생하셨습니다.

@DongEun02 DongEun02 merged commit b342bda into main Nov 26, 2025
1 check passed
@DongEun02 DongEun02 deleted the SISC1-210-FE branch November 26, 2025 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants