Skip to content

THIP-389: 지현 주석 및 개발 로그 제거#296

Merged
ljh130334 merged 7 commits intoTHIP-386from
THIP-389
Nov 26, 2025
Merged

THIP-389: 지현 주석 및 개발 로그 제거#296
ljh130334 merged 7 commits intoTHIP-386from
THIP-389

Conversation

@ljh130334
Copy link
Member

@ljh130334 ljh130334 commented Nov 25, 2025

#️⃣ 연관된 이슈

THIP-389

📝 작업 내용

작업 목적

코드베이스 전반에 걸쳐 불필요한 주석을 제거하여 코드 가독성과 유지보수성을 개선했습니다.

작업 배경

  • TypeScript 타입 시스템이 충분한 문서화 역할을 수행하고 있음에도 불구하고, 중복되는 주석이 산재해 있었습니다.
  • 사용 예시 코드 블록이 실제 코드와 동기화되지 않아 오히려 혼란을 야기할 가능성이 있었습니다.
  • "타입이 곧 문서"라는 TypeScript의 철학에 맞게 코드를 간결하게 정리할 필요가 있었습니다.

작업 내용

1️⃣ API 함수 주석 제거 (a26327e)

  • API 파일에서 JSDoc 주석 제거
  • 인터페이스/타입 설명 주석 제거
  • 사용 예시 코드 블록 제거
  • 영향 파일: src/api/ 하위 feeds, record, rooms, images 등

2️⃣ Components 주석 제거 (0be3cb7)

  • React 컴포넌트의 props, 함수 설명 주석 제거
  • 컴포넌트 동작 설명 주석 정리
  • 영향 범위: src/components/ 전체

3️⃣ Hooks 주석 제거 (2bbe02b)

  • 커스텀 훅의 파라미터, 반환값 설명 주석 제거
  • 훅 사용법 예시 제거
  • 영향 범위: src/hooks/ 또는 src/shared/hooks/

4️⃣ Pages 주석 제거 (6fd86e5)

  • 페이지 컴포넌트의 설명 주석 제거
  • 페이지 구조 설명 주석 정리
  • 영향 범위: src/pages/

5️⃣ Global 설정 주석 제거 (a1ce57e)

  • 전역 스타일 사용 예시 주석 제거
  • 영향 파일: src/shared/config/global/

6️⃣ Types, Utils 주석 제거 (0c7f553)

  • 타입 정의 설명 주석 제거
  • 유틸 함수 설명 주석 제거
  • 영향 범위: src/types/, src/utils/ 또는 src/shared/lib/

개선 효과

  • 가독성 향상: 코드와 타입 정의만으로 의도를 파악할 수 있게 됨
  • 유지보수성 개선: 주석과 코드의 불일치 문제 해소
  • 코드량 감소: 불필요한 주석 제거로 파일 크기 축소
  • TypeScript 활용 극대화: 타입 시스템을 통한 자연스러운 문서화

💬 리뷰 요구사항(선택)

  • 혹시 제거하지 말았어야 할 중요한 주석이 있는지 확인해주세요.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • AI 글쓰기 기능에 사용량 검증 및 확인 모달 추가
    • 멤버 프로필 네비게이션 개선
    • 비밀번호 입력 필드에 4자리 숫자 제한 추가
  • 버그 수정

    • 글 업데이트 실패 시 대체 통신 방식으로 재시도
    • ISBN 정규화 로직 개선
    • API 오류 시 사용자 친화적 메시지 표시
  • 개선사항

    • 멤버 정보에 프로필 이미지 및 가입일 필드 추가
    • API 응답 타입 확장으로 메시지 및 데이터 필드 포함

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

@vercel
Copy link

vercel bot commented Nov 25, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
thip Ready Ready Preview Comment Nov 25, 2025 6:24am

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

주석, 문서화 블록 및 개발 로그를 제거하는 대규모 정리 작업입니다. 일부 API 함수의 폴백 메커니즘(multipart/form-data), 타입 확장(profileImageUrl, joinedAt 등), 오류 처리 개선사항도 포함됩니다.

Changes

Cohort / File(s) Summary
API 피드 및 기본 업데이트
src/api/feeds/createFeed.ts, src/api/feeds/updateFeed.ts, src/api/feeds/getWriteInfo.ts
함수 서명 리포매팅, 인라인 문서 제거. updateFeed에 JSON 요청 실패 시 multipart/form-data 폴백 추가. GetWriteInfoResponse 타입 제거.
API 기록 및 투표 CRUD
src/api/record/create*.ts, src/api/record/delete*.ts, src/api/record/update*.ts, src/api/record/get*.ts, src/api/record/pin*.ts, src/api/record/post*.ts
사용 예제 블록, 문서화 주석, 콘솔 로그 제거. 타입 별칭 제거(CreateRecordResponse, CreateAiReviewResponse 등). 기능 변경 없음.
API 이미지 및 룸 포스트
src/api/images/uploadImage.ts, src/api/roomPosts/postRoomPostLike.ts, src/api/memory/getMemoryPosts.ts
레거시 사용 예제, 인라인 주석 제거. 함수 서명 및 동작 변경 없음.
API 룸 관리
src/api/rooms/create*.ts, src/api/rooms/delete*.ts, src/api/rooms/get*.ts, src/api/rooms/leave*.ts
문서화 주석, 사용 예제 블록 제거. 타입 및 함수 서명 유지.
UI 컴포넌트: 책 검색
src/components/common/BookSearchBottomSheet/BookList.tsx, src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.tsx, src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.styled.ts, src/components/common/BookSearchBottomSheet/useBookSearch.ts
주석 제거, JSX 리포매팅. body 스크롤 라이프사이클 관리 추가(열기: overflow hidden, 닫기: 정리). isLoadingMore, isSearchMode 상태 전파.
UI 컴포넌트: 댓글 및 포스트
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx, src/components/common/Post/Reply.tsx, src/components/common/Post/SubReply.tsx
주석 제거. Reply/SubReply의 좋아요 성공/실패 콘솔 로그 제거. 기능 유지.
UI 컴포넌트: 그룹 생성
src/components/creategroup/ActivityPeriodSection/ActivityPeriodSection.tsx, src/components/creategroup/ActivityPeriodSection/DateWheel.tsx, src/components/creategroup/MemberLimitSection.tsx, src/components/creategroup/PrivacySettingSection/PasswordInputSection.styled.ts, src/components/creategroup/PrivacySettingSection/PasswordInputSection.tsx
주석 제거. PasswordInputSection에 onKeyDown으로 4자리 숫자 입력 제한 추가.
UI 컴포넌트: 포스트 생성
src/components/createpost/PhotoSection.tsx, src/components/createpost/PostContentSection.styled.ts, src/components/createpost/TagSelectionSection.tsx
인라인 주석 제거. TagSelectionSection에 로딩 상태 명시적 설정 추가.
UI 컴포넌트: 메모리 및 음성
src/components/memory/MemoryAddButton/MemoryAddButton.tsx, src/components/memory/MemoryContent/MemoryContent.tsx, src/components/memory/RecordFilters/PageInputMode.styled.ts, src/components/memory/RecordFilters/RecordFilters.tsx, src/components/memory/RecordItem/PollRecord.tsx, src/components/memory/RecordItem/RecordItem.tsx, src/components/memory/SortDropdown.tsx, src/components/memory/UploadProgressBar/UploadProgressBar.tsx
MemoryAddButton에 AI 사용량 검증 및 모달 확인 흐름 추가. 주석 제거, 콘솔 로그 제거. RecordItem 클릭 핸들러 통합/단순화.
UI 컴포넌트: 투표 및 기록 작성
src/components/pollwrite/PollCreationSection.tsx, src/components/recordwrite/PageRangeSection.styled.ts, src/components/recordwrite/PageRangeSection.tsx, src/components/recordwrite/RecordContentSection.tsx
PollCreationSection에 기본값 추가(isEditMode=false, autoFocus=false). RecordContentSection에 autoFocus=false 기본값 추가. 주석 제거.
UI 컴포넌트: 그룹 및 회원
src/components/group/GroupActionBottomSheet.tsx, src/components/group/HotTopicSection.tsx, src/components/members/MemberList.tsx
주석 제거. MemberList에서 onMemberClick 미제공 시 /otherfeed/{id}로 명시적 라우팅 추가.
UI 컴포넌트: 오늘의 한마디
src/components/today-words/MessageInput.styled.ts, src/components/today-words/MessageInput.tsx, src/components/today-words/MessageList/MessageActionBottomSheet.tsx, src/components/today-words/MessageList/MessageList.tsx
주석 및 IE/Edge 스크롤바 스타일 제거. MessageList에 addMessage 구현 및 useImperativeHandle 추가. initialMessages 동기화 effect 추가.
페이지: 그룹 및 메모리
src/pages/group/CreateGroup.tsx, src/pages/groupDetail/ParticipatedGroupDetail.tsx, src/pages/groupMembers/GroupMembers.tsx
임포트 경로 수정, 주석 및 콘솔 로그 제거. 기능 유지.
페이지: 메모리
src/pages/memory/Memory.styled.ts, src/pages/memory/Memory.tsx
Memory.tsx에서 상태 대폭 제거(isOverviewEnabled, roomCompleted, totalPages, currentUserPage). API 데이터 핸들링, 파생 상태 간소화. 주석 정리.
페이지: 투표 및 기록 작성
src/pages/pollwrite/PollWrite.tsx, src/pages/recordwrite/RecordWrite.tsx
주석 제거. HTTP 400 오류 메시지 일반화("입력값을 확인해 주세요."). 기능 유지.
페이지: 포스트 및 오늘의 말
src/pages/post/CreatePost.tsx, src/pages/post/UpdatePost.tsx, src/pages/today-words/TodayWords.tsx
CreatePost의 useCreateFeed onSuccess 콜백 시그니처 변경(feedId 매개변수 제거). UpdatePost 콘솔 로그 제거. TodayWords에 try/catch/finally 및 HTTP 에러 코드 매핑 추가.

src/hooks/useCreateFeed.ts, src/hooks/useUpdateFeed.ts
useCreateFeed에 snackbar variant/onClose 일관성 추가. 유효성 검사 로직 유지. useUpdateFeed 주석 제거.
저장소 및 유틸
src/stores/useCommentBottomSheetStore.ts, src/stores/usePopupStore.ts, src/utils/isbn.ts, src/utils/roomStatus.ts, src/styles/global/global.ts, src/mocks/members.mock.ts
주석 제거, 리포매팅. isbn의 normalizeIsbn에 toUpperCase() 추가. 기능 대부분 유지.
타입 정의
src/types/memory.ts, src/types/record.ts, src/types/room.ts, src/types/roomPostLike.ts, src/types/today.ts
Record에 profileImageUrl: string 추가. RoomMember에 profileImageUrl?: string, joinedAt: string 추가. ApiResponse에 message: string, data: T 추가. 인라인 주석 정리.

Sequence Diagram

sequenceDiagram
    participant User
    participant MemoryAddButton
    participant API as API (getAiUsage)
    participant Modal
    participant Page as AI Write Page

    User->>MemoryAddButton: Click "AI 작성"
    MemoryAddButton->>API: Check AI Usage & Records
    
    alt recordCount < 2
        API-->>MemoryAddButton: Insufficient records
        MemoryAddButton->>User: Show error snackbar
    else recordReviewCount >= 5
        API-->>MemoryAddButton: Limit exceeded
        MemoryAddButton->>User: Show error snackbar
    else Eligible
        API-->>MemoryAddButton: Usage OK
        MemoryAddButton->>Modal: Open confirmation modal
        User->>Modal: Confirm
        Modal->>Page: Navigate to AI write
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

주의가 필요한 영역:

  • src/api/feeds/updateFeed.ts: JSON 요청 실패 시 multipart/form-data 폴백 로직의 정확성 검증 필요
  • src/pages/memory/Memory.tsx: 상태 대폭 제거로 인한 렌더링 로직 및 페이지네이션 동작 재검증 필수
  • src/components/memory/MemoryAddButton/MemoryAddButton.tsx: AI 사용량 검증 흐름과 모달 확인 로직의 오류 처리 확인
  • src/pages/today-words/TodayWords.tsx: HTTP 에러 코드 매핑과 사용자 친화적 메시지 전파 동작 확인
  • src/components/recordwrite/RecordContentSection.tsx: autoFocus 의존성 및 useEffect 재실행 타이밍 검증
  • src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.tsx: body 스크롤 라이프사이클 정리 및 상태 전파 로직

Possibly related PRs

Suggested labels

📝 cleanup, 🔧 refactor, 📃 Docs

Suggested reviewers

  • ho0010
  • heeeeyong

Poem

🐰 주석 지우고 로그 없애니,
코드가 더 깨끗해졌어!
폴백 로직도 챙기고,
타입도 명확하게 다듬었네,
텍스트힙의 정리 정돈, 우리 함께 완성! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive 대부분의 변경이 주석 및 로그 제거에 해당하지만, 일부 기능적 변경사항들이 포함되어 있어 범위 검토가 필요합니다. 다음 기능적 변경사항들의 필요성을 확인하세요: updateFeed의 multipart/form-data 폴백 처리, PasswordInputSection의 4자리 숫자 제한 로직, RecordContentSection의 autoFocus 기본값, Memory.tsx의 대규모 상태 제거 등이 이슈 범위에 포함되는지 검증하십시오.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주석 및 개발 로그 제거라는 변경의 핵심을 명확하게 설명하고 있으며, 이슈 번호(THIP-389)를 포함하여 구체적입니다.
Linked Issues check ✅ Passed 변경 사항이 주석 및 개발 로그 제거라는 이슈 목표와 일치하며, 코드베이스 전반의 불필요한 주석, 사용 예시, 개발 로그를 체계적으로 제거했습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch THIP-389

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • THIP-389: Request failed with status code 404

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

Caution

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

⚠️ Outside diff range comments (1)
src/api/rooms/getBookPage.ts (1)

17-25: 반환값 불일치로 인한 호출 에러 수정 필요

검증 결과, 원래 리뷰 지적이 정확합니다. 함수 구현에 중대한 오류가 있습니다:

  • 함수 시그니처: Promise<BookPageResponse> 선언 (20행)
  • 실제 반환값: response.data (20행)
  • 호출자들의 기대값: RecordWrite.tsx(65-66행), PollWrite.tsx(76-77행)에서 모두 response.isSuccess 접근

현재 코드는 호출자들을 런타임 에러로 이끕니다. 호출자들이 response.isSuccess를 접근할 때 해당 속성이 없어 실패합니다.

수정 방안:

전체 응답을 반환하도록 변경:

-export const getBookPage = async (roomId: number): Promise<BookPageResponse> => {
+export const getBookPage = async (roomId: number): Promise<BookPageResponse> => {
   try {
     const response = await apiClient.get<BookPageResponse>(`/rooms/${roomId}/book-page`);
-    return response.data;
+    return response.data; // response.data는 BookPageResponse 구조: { isSuccess, code, message, data: BookPageData }
   } catch (error) {
     console.error('책 페이지 정보 조회 API 오류:', error);
     throw error;
   }
 };

또는 반환 타입을 BookPageData로 변경하고 모든 호출자 코드도 함께 수정해야 합니다.

🧹 Nitpick comments (14)
src/pages/memory/Memory.styled.ts (1)

23-45: ScrollableContent 주석 제거는 안전해 보입니다

  • padding-bottom: 100px; 및 스크롤바 스타일 등 실제 스타일 값/구조는 변경되지 않아 레이아웃과 동작에는 영향이 없어 보입니다.
  • 이전 주석(하단 버튼 공간 확보, 스크롤바 스타일링)은 코드만 봐도 용도가 충분히 추론 가능해서, 이번 PR 목적(불필요한 주석 정리)에 잘 부합한다고 판단됩니다.

추가로, 별도 작업 기회가 있으면 100px를 디자인 토큰/공통 spacing 값으로 추출하는 정도만 고려해 볼 수 있겠습니다(이번 PR에서 필수는 아님).

src/pages/groupMembers/GroupMembers.tsx (1)

42-53: 오류 처리 로직은 적절하나, 빈 줄 정리 및 콘솔 로그 검토 필요

코드 레벨에서는 문제가 없습니다. 권한 없음 오류에 대한 특정 처리(/group로 네비게이션)는 좋은 방식입니다. 다만:

  1. 43번 줄: console.error 호출이 프로덕션 환경에서 적절한지 검토해주세요. 프로덕션에서 에러 로깅이 필요하다면 구조화된 로거(예: Sentry 등)로 마이그레이션하는 것을 추천합니다.
  2. 44번, 49번 줄: 주석 제거 후 남은 빈 줄입니다. 가독성상 불필요한 빈 줄을 제거하거나 한 줄만 유지하는 것을 고려하세요.

다음과 같이 정리할 수 있습니다:

       try {
         setLoading(true);
         const response: RoomMembersResponse = await getRoomMembers(parseInt(currentRoomId));
 
         if (response.isSuccess) {
           const convertedMembers = convertRoomMembersToMembers(response.data.userList);
           setMembers(convertedMembers);
         } else {
           setError(response.message);
         }
       } catch (err: unknown) {
         console.error('독서메이트 조회 오류:', err);
-        
         if (err instanceof Error && err.message === '방 접근 권한이 없습니다.') {
           navigate('/group', { replace: true });
           return;
         }
-        
         setError('독서메이트 목록을 불러오는 중 오류가 발생했습니다.');
       } finally {
         setLoading(false);
       }
src/components/memory/MemoryAddButton/MemoryAddButton.tsx (1)

41-41: 매직 넘버 '1' 중복 사용 개선 권장

roomId || '1' 패턴이 세 군데에서 반복됩니다. 기본값을 상수로 추출하면 유지보수성이 향상됩니다.

 const MemoryAddButton = () => {
   const navigate = useNavigate();
   const { roomId } = useParams<{ roomId: string }>();
+  const currentRoomId = roomId || '1';
   const { openConfirm, closePopup, openSnackbar } = usePopupActions();
   // ...

   const handleRecordWrite = () => {
     setIsOpen(false);
-    const currentRoomId = roomId || '1';
     navigate(`/memory/record/write/${currentRoomId}`);
   };

   const handlePollCreate = () => {
     setIsOpen(false);
-    const currentRoomId = roomId || '1';
     navigate(`/memory/poll/write/${currentRoomId}`);
   };

   const handleAIWrite = async () => {
     setIsOpen(false);
-    const currentRoomId = roomId || '1';
     // ...
   };

Also applies to: 49-49, 56-56

src/types/record.ts (1)

27-44: VoteItemResult 중복 정의 및 VoteRequest.type(boolean) 의미 모호성 리팩터 제안

  • VoteItemResult의 필드 구성이 src/types/memory.tsVoteItem과 완전히 동일해서, 파일만 다를 뿐 사실상 같은 타입이 이중 정의되어 있습니다. 장기적으로는 하나의 공용 타입으로 통합하고 필요한 곳에서만 import 하는 구조로 리팩터링하면 유지보수성이 좋아질 것 같습니다.
  • VoteRequesttype: boolean은 (이 PR에서 주석이 제거된 상태라면) true/false가 어떤 의미인지 한눈에 파악하기 어렵습니다. 후속 리팩터링에서
    type: 'UP' | 'DOWN' 같은 string literal union이나 enum으로 의미를 드러내는 쪽을 고려해 보시면 좋겠습니다.

현재 PR 범위를 넘는 변경이니 참고용 제안으로만 받아주시면 될 것 같습니다.

src/components/recordwrite/RecordContentSection.tsx (1)

36-45: 중복된 adjustHeight() 호출 제거 고려

autoFocus가 변경될 때마다 adjustHeight()가 호출되는데, 이는 32-34번 줄에서 이미 content 변경 시 호출되고 있어 중복입니다. 이 useEffect의 주 목적은 포커스 처리이므로 37번 줄의 adjustHeight() 호출은 불필요해 보입니다.

다음과 같이 수정할 수 있습니다:

 useEffect(() => {
-  adjustHeight();
-
   if (autoFocus && textareaRef.current) {
     const textarea = textareaRef.current;
     textarea.focus();
     const length = textarea.value.length;
     textarea.setSelectionRange(length, length);
   }
 }, [autoFocus]);
src/pages/pollwrite/PollWrite.tsx (1)

254-271: 오류 메시지 구체성 고려

HTTP 400 오류 시 일반적인 메시지("입력값을 확인해 주세요.")로 변경되었습니다. 이전에는 수정/생성 모드에 따라 다른 메시지를 제공했을 가능성이 있습니다. 사용자 경험 측면에서 더 구체적인 메시지(예: "투표 수정 중 입력값 오류", "투표 생성 중 입력값 오류")가 도움이 될 수 있습니다.

src/components/today-words/MessageList/MessageList.tsx (2)

52-58: 타임스탬프 포맷팅 로직에 간단한 설명 추가를 고려해보세요.

날짜 포맷팅 로직이 다소 복잡합니다. 정규식을 사용한 replace 체이닝의 목적(공백 제거 및 마지막 점 제거)을 한 줄로 설명하면 향후 유지보수에 도움이 될 수 있습니다. 하지만 코드 자체로도 충분히 이해 가능하므로 필수는 아닙니다.


70-84: 날짜별 그룹핑 로직에 대한 간단한 설명을 고려해보세요.

메시지를 날짜별로 그룹화하고 정렬하는 로직입니다. 코드는 정확하지만, 타입 정의만으로는 "날짜별 구분선 렌더링을 위한 그룹핑"이라는 의도가 명확하지 않을 수 있습니다. 한 줄 주석 추가를 고려해보세요. 단, 코드 가독성이 이미 양호하므로 선택 사항입니다.

src/components/memory/RecordFilters/RecordFilters.tsx (1)

61-106: 페이지 범위 유효성 검증 로직이 입력 플로우와 잘 정합됨

handleConfirm에서의 검증 조건(양수 & 시작 ≤ 끝)과 isValid 계산식이 동일하게 맞춰져 있어, 버튼 활성화 조건과 실제 확정 조건이 어긋나지 않는 점이 좋습니다. parseInt 호출이 여러 번 등장하긴 하지만 현재 규모에서는 크게 문제될 부분은 아니며, 필요 시 나중에 시작/끝 값을 한 번만 계산해 재사용하는 방식으로 리팩터링해도 될 것 같습니다.

src/components/common/BookSearchBottomSheet/BookList.tsx (1)

29-59: BookList의 IntersectionObserver는 정상 동작하나, isSearchMode 사용 여부를 한 번 정리해도 좋겠습니다.

lastBookElementRef 콜백의 의존성 배열에는 isSearchMode가 들어가 있지만, 콜백 본문에서는 isSearchMode를 읽지 않고 있습니다.

  • 만약 검색 모드일 때 무한 스크롤을 막으려는 의도라면, entries[0].isIntersecting && hasNextPage && onLoadMore && !isSearchMode처럼 조건에 명시적으로 포함하는 쪽이 의도가 더 분명할 것 같습니다.
  • 반대로 실제로는 상위에서 hasNextPage/onLoadMore로 이미 제어하고 있어 의미가 없다면, 의존성 배열에서 isSearchMode를 제거해 약간이라도 불필요한 재생성을 줄이는 것도 고려해 볼 수 있습니다.
src/pages/recordwrite/RecordWrite.tsx (1)

32-121: RecordWrite의 초기화/저장 로직은 안정적으로 보이며, isLoading·에러 처리 부분은 소폭 정리 여지가 있습니다.

  • initializeData 안에서 수정 모드인 경우 setIsLoading(false); 호출 후 return하고, finally에서도 다시 setIsLoading(false);를 호출합니다. 동작에는 영향이 없지만 수정 모드 경로에서 동일한 state 업데이트가 두 번 발생하므로, try 블록 내부의 setIsLoading(false);는 제거해도 될 것 같습니다.
  • 책 정보 로딩 실패 시와 기록 생성/수정 실패 시 모두, axiosError.response.data.messagecode(400/403/404)에 따라 사용자 메시지를 만드는 로직이 거의 동일합니다. 이 부분을 작은 유틸 함수나 헬퍼로 뽑아 두면, 에러 코드가 늘어나거나 메시지를 수정할 때 한 곳만 손보면 되어 유지보수성이 좋아질 것 같습니다.

PageRangeSection에 넘기는 readingProgress, isDisabled, hideToggle 값 자체는 명확해서, 이 부분의 주석 제거는 동작이나 이해에 문제 없어 보입니다.

Also applies to: 138-255, 294-305

src/pages/today-words/TodayWords.tsx (3)

35-57: 오늘 날짜 문자열 비교 방식이 포맷/스펙 변경에 취약합니다

getTodayDateStrings에서 여러 문자열 포맷을 만들고, getTodayMyMessageCount에서 message.timestamp와 단순 문자열 비교로 오늘 여부를 판별하고 있습니다. 서버에서 내려오는 item.date 포맷이나 타임존 스펙이 바뀌면(예: ISO 문자열, 다른 구분자 등) 오늘 카운트가 어긋날 수 있습니다.

API 스펙이 충분히 고정이라면 문제는 없지만,

  • 가능한 한 서버에서 내려주는 하나의 표준 포맷만 사용하거나,
  • timestampDate로 파싱해서 연/월/일 기준으로 비교하는 등

조금 더 견고한 방식으로 개선하는 것도 한 번 고려해 보셔도 좋겠습니다.


65-79: createdAt를 클라이언트 현재 시각으로 두는 것이 의도인지 확인이 필요합니다

convertToMessage에서 createdAt을 항상 new Date()로 세팅하고 있어, 서버에서의 실제 작성 시각과는 무관하게 “가져온 시점” 기준 시간이 들어가게 됩니다.

이 필드가:

  • 단순히 리스트 내 임시 정렬/키 용도라면 큰 문제는 없지만,
  • 메시지 정렬, 이후 통계/필터 등 시간 기반 로직에 활용된다면 재진입 시마다 값이 달라져 정렬이 흔들릴 수 있습니다.

혹시 서버에서 실제 생성 시각(예: ISO datetime)을 제공하고 있다면, 그 값을 기준으로 createdAt을 세팅하는 편이 더 안전한지 한 번 점검을 부탁드립니다.


318-325: 초기 로딩 스피너 레이아웃 인라인 스타일 적용은 적절해 보입니다

초기 로딩 시 중앙 정렬을 위해 wrapper div에 플렉스, 높이 200px을 주는 변경은 시각적으로 더 명확한 로딩 상태를 제공하면서도 부수 영향이 거의 없어 보입니다. 추후 반복 사용 시에는 styled 컴포넌트로의 추출 정도만 고려하시면 될 것 같습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f4a52ab and c7ef2a7.

📒 Files selected for processing (81)
  • src/api/feeds/createFeed.ts (1 hunks)
  • src/api/feeds/getWriteInfo.ts (0 hunks)
  • src/api/feeds/updateFeed.ts (0 hunks)
  • src/api/images/uploadImage.ts (1 hunks)
  • src/api/memory/getMemoryPosts.ts (1 hunks)
  • src/api/record/createAiReview.ts (0 hunks)
  • src/api/record/createRecord.ts (0 hunks)
  • src/api/record/createVote.ts (0 hunks)
  • src/api/record/deleteRecord.ts (1 hunks)
  • src/api/record/deleteVote.ts (1 hunks)
  • src/api/record/getAiUsage.ts (1 hunks)
  • src/api/record/pinRecordToFeed.ts (1 hunks)
  • src/api/record/postVote.ts (1 hunks)
  • src/api/record/updateRecord.ts (0 hunks)
  • src/api/record/updateVote.ts (0 hunks)
  • src/api/roomPosts/postRoomPostLike.ts (0 hunks)
  • src/api/rooms/createDailyGreeting.ts (1 hunks)
  • src/api/rooms/createRoom.ts (0 hunks)
  • src/api/rooms/deleteDailyGreeting.ts (1 hunks)
  • src/api/rooms/getBookPage.ts (1 hunks)
  • src/api/rooms/getDailyGreeting.ts (1 hunks)
  • src/api/rooms/getRoomMembers.ts (1 hunks)
  • src/api/rooms/getRoomPlaying.ts (0 hunks)
  • src/api/rooms/leaveRoom.ts (1 hunks)
  • src/components/common/BookSearchBottomSheet/BookList.tsx (4 hunks)
  • src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.styled.ts (0 hunks)
  • src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.tsx (3 hunks)
  • src/components/common/BookSearchBottomSheet/useBookSearch.ts (5 hunks)
  • src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (4 hunks)
  • src/components/common/Post/Reply.tsx (0 hunks)
  • src/components/common/Post/SubReply.tsx (0 hunks)
  • src/components/creategroup/ActivityPeriodSection/ActivityPeriodSection.tsx (1 hunks)
  • src/components/creategroup/ActivityPeriodSection/DateWheel.tsx (0 hunks)
  • src/components/creategroup/MemberLimitSection.tsx (0 hunks)
  • src/components/creategroup/PrivacySettingSection/PasswordInputSection.styled.ts (0 hunks)
  • src/components/creategroup/PrivacySettingSection/PasswordInputSection.tsx (1 hunks)
  • src/components/createpost/PhotoSection.tsx (0 hunks)
  • src/components/createpost/PostContentSection.styled.ts (0 hunks)
  • src/components/createpost/TagSelectionSection.tsx (0 hunks)
  • src/components/group/GroupActionBottomSheet.tsx (1 hunks)
  • src/components/group/HotTopicSection.tsx (1 hunks)
  • src/components/members/MemberList.tsx (0 hunks)
  • src/components/memory/MemoryAddButton/MemoryAddButton.tsx (1 hunks)
  • src/components/memory/MemoryContent/MemoryContent.tsx (0 hunks)
  • src/components/memory/RecordFilters/PageInputMode.styled.ts (0 hunks)
  • src/components/memory/RecordFilters/RecordFilters.tsx (1 hunks)
  • src/components/memory/RecordItem/PollRecord.tsx (5 hunks)
  • src/components/memory/RecordItem/RecordItem.tsx (8 hunks)
  • src/components/memory/SortDropdown.tsx (0 hunks)
  • src/components/memory/UploadProgressBar/UploadProgressBar.tsx (2 hunks)
  • src/components/pollwrite/PollCreationSection.tsx (1 hunks)
  • src/components/recordwrite/PageRangeSection.styled.ts (0 hunks)
  • src/components/recordwrite/PageRangeSection.tsx (1 hunks)
  • src/components/recordwrite/RecordContentSection.tsx (2 hunks)
  • src/components/today-words/MessageInput.styled.ts (0 hunks)
  • src/components/today-words/MessageInput.tsx (1 hunks)
  • src/components/today-words/MessageList/MessageActionBottomSheet.tsx (0 hunks)
  • src/components/today-words/MessageList/MessageList.tsx (2 hunks)
  • src/hooks/useCreateFeed.ts (2 hunks)
  • src/hooks/useUpdateFeed.ts (0 hunks)
  • src/mocks/members.mock.ts (1 hunks)
  • src/pages/group/CreateGroup.tsx (3 hunks)
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx (3 hunks)
  • src/pages/groupMembers/GroupMembers.tsx (1 hunks)
  • src/pages/memory/Memory.styled.ts (1 hunks)
  • src/pages/memory/Memory.tsx (1 hunks)
  • src/pages/pollwrite/PollWrite.tsx (7 hunks)
  • src/pages/post/CreatePost.tsx (3 hunks)
  • src/pages/post/UpdatePost.tsx (1 hunks)
  • src/pages/recordwrite/RecordWrite.tsx (1 hunks)
  • src/pages/today-words/TodayWords.tsx (4 hunks)
  • src/stores/useCommentBottomSheetStore.ts (1 hunks)
  • src/stores/usePopupStore.ts (0 hunks)
  • src/styles/global/global.ts (0 hunks)
  • src/types/memory.ts (2 hunks)
  • src/types/record.ts (1 hunks)
  • src/types/room.ts (1 hunks)
  • src/types/roomPostLike.ts (1 hunks)
  • src/types/today.ts (0 hunks)
  • src/utils/isbn.ts (1 hunks)
  • src/utils/roomStatus.ts (0 hunks)
💤 Files with no reviewable changes (31)
  • src/components/creategroup/ActivityPeriodSection/DateWheel.tsx
  • src/types/today.ts
  • src/components/common/Post/Reply.tsx
  • src/components/memory/SortDropdown.tsx
  • src/api/roomPosts/postRoomPostLike.ts
  • src/components/creategroup/MemberLimitSection.tsx
  • src/api/record/updateRecord.ts
  • src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.styled.ts
  • src/hooks/useUpdateFeed.ts
  • src/components/today-words/MessageInput.styled.ts
  • src/api/record/createRecord.ts
  • src/components/createpost/PostContentSection.styled.ts
  • src/components/creategroup/PrivacySettingSection/PasswordInputSection.styled.ts
  • src/components/recordwrite/PageRangeSection.styled.ts
  • src/api/rooms/getRoomPlaying.ts
  • src/utils/roomStatus.ts
  • src/components/members/MemberList.tsx
  • src/components/memory/MemoryContent/MemoryContent.tsx
  • src/api/record/updateVote.ts
  • src/components/common/Post/SubReply.tsx
  • src/styles/global/global.ts
  • src/components/today-words/MessageList/MessageActionBottomSheet.tsx
  • src/api/feeds/getWriteInfo.ts
  • src/api/rooms/createRoom.ts
  • src/stores/usePopupStore.ts
  • src/components/createpost/PhotoSection.tsx
  • src/api/record/createAiReview.ts
  • src/components/memory/RecordFilters/PageInputMode.styled.ts
  • src/api/feeds/updateFeed.ts
  • src/api/record/createVote.ts
  • src/components/createpost/TagSelectionSection.tsx
🧰 Additional context used
🧬 Code graph analysis (14)
src/pages/pollwrite/PollWrite.tsx (2)
src/api/rooms/getBookPage.ts (1)
  • getBookPage (17-25)
src/api/record/createVote.ts (1)
  • createVote (6-9)
src/components/memory/RecordItem/PollRecord.tsx (2)
src/types/memory.ts (1)
  • PollOption (75-83)
src/components/memory/RecordItem/PollRecord.styled.ts (1)
  • PollOption (23-32)
src/api/rooms/getDailyGreeting.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
src/components/common/BookSearchBottomSheet/BookList.tsx (1)
src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.styled.ts (2)
  • BookList (159-163)
  • BookItem (165-177)
src/api/record/getAiUsage.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
src/components/common/BookSearchBottomSheet/useBookSearch.ts (1)
src/api/books/getSearchBooks.ts (2)
  • getSearchBooks (41-59)
  • convertToSearchedBooks (61-70)
src/types/record.ts (1)
src/types/memory.ts (1)
  • VoteItem (1-7)
src/pages/post/CreatePost.tsx (2)
src/utils/isbn.ts (1)
  • ensureIsbn13 (16-21)
src/hooks/useCreateFeed.ts (1)
  • useCreateFeed (11-157)
src/api/record/postVote.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
src/pages/today-words/TodayWords.tsx (2)
src/types/today.ts (2)
  • TodayCommentItem (12-21)
  • Message (1-10)
src/api/rooms/getDailyGreeting.ts (1)
  • getDailyGreeting (20-34)
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (2)
src/api/comments/postReply.ts (1)
  • postReply (19-31)
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.styled.ts (2)
  • Content (49-53)
  • LoadingState (55-63)
src/pages/group/CreateGroup.tsx (1)
src/types/room.ts (1)
  • CreateRoomRequest (20-30)
src/types/memory.ts (1)
src/types/record.ts (1)
  • VoteItem (11-13)
src/components/today-words/MessageList/MessageList.tsx (1)
src/api/rooms/deleteDailyGreeting.ts (1)
  • deleteDailyGreeting (12-26)
🔇 Additional comments (65)
src/mocks/members.mock.ts (1)

11-18: 주석 제거 확인됨 — mock 데이터에서는 안전합니다.

이 변경은 Member 객체의 profileImage 필드에서 인라인 주석을 제거하는 것으로, 런타임 동작이나 데이터 구조에는 영향을 주지 않습니다. Mock 데이터 파일에서의 주석 제거는 PR 목표와 일치하며, TypeScript 인터페이스(1-8줄)가 충분한 타입 정보를 제공하므로 안전한 변경입니다.

다만, 제거된 주석이 테스트/개발 과정에서 중요한 정보를 담고 있지 않았는지 확인해 주시기 바랍니다.

src/components/today-words/MessageInput.tsx (1)

89-89: 주석 제거 후 코드 가독성이 잘 유지되고 있습니다.

MessageInputProps 인터페이스가 이미 명확한 타입 정보를 제공하고 있으며, 남은 코드 로직이 직관적이어서 제거된 주석이 없어도 의도가 명확합니다. 특히:

  • Line 89: disabled 상태에 따른 placeholder 전환 로직이 자체 설명적(self-documenting)입니다.
  • Line 93: 조합 입력(composition) 상태 관리가 변수명과 핸들러 네이밍으로 충분히 이해됩니다.

TypeScript 타입 시스템이 주석을 효과적으로 대체하고 있어, PR의 목표(주석 정리를 통한 가독성 및 유지보수성 개선)가 이 컴포넌트에서는 잘 달성되었습니다.

Also applies to: 93-93

src/pages/groupMembers/GroupMembers.tsx (1)

59-70: 멤버 네비게이션 로직 승인

handleMemberClick의 자기 자신 여부 확인 후 다른 라우트로 분기하는 로직이 명확하고 효율적입니다. 이 구현 방식은 좋습니다.

src/stores/useCommentBottomSheetStore.ts (1)

14-25: LGTM! 포맷팅 개선이 가독성을 향상시킵니다.

제네릭 타입 선언 및 함수 구현의 포맷팅 변경이 코드의 가독성을 개선하며, 런타임 동작이나 타입 안전성에는 영향을 주지 않습니다. PR의 목표인 코드 정리 및 가독성 향상에 잘 부합합니다.

src/components/memory/MemoryAddButton/MemoryAddButton.tsx (2)

13-13: LGTM!

주석 제거 작업이 정상적으로 반영되었습니다. useParams 타입 정의가 명확하게 유지되어 있습니다.


54-111: LGTM!

handleAIWrite 함수의 구현이 잘 되어 있습니다:

  • API 호출에 대한 try-catch 에러 처리가 적절합니다
  • 기록 개수 및 이용 횟수 검증 로직이 명확합니다
  • 사용자에게 적절한 피드백(snackbar, confirm modal)을 제공합니다
src/components/creategroup/ActivityPeriodSection/ActivityPeriodSection.tsx (2)

41-44: 변경 사항 확인 필요

AI 요약에서는 "실행 로직이 수정되지 않았다"고 명시되어 있으나, 43번 라인이 변경된 것으로 표시되어 있습니다. 이것이 단순히 주변 주석 제거로 인한 것인지, 아니면 실제 로직 변경이 있었는지 확인해 주세요.

현재 날짜 차이 계산 로직 자체는 정확합니다 (시작일과 종료일 모두 포함하는 inclusive counting).


1-248: 주석 제거 완료, LGTM!

전체적으로 코드 구조와 로직이 잘 유지되어 있습니다. 날짜 유효성 검사, 범위 계산, 핸들러 로직 모두 정상적으로 동작할 것으로 보입니다.

src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (3)

32-32: 코드 정리 변경사항이 적절합니다.

빈 줄 추가 및 trailing comma 적용은 코드 가독성과 Git diff 품질을 개선하는 모범 사례입니다. 기능적 변경 없이 코드 스타일만 개선되었습니다.

Also applies to: 66-66, 73-73, 146-146


151-151: 컴포넌트 포맷팅 변경이 적절합니다.

ReplyList 컴포넌트를 단일 라인으로 변경한 것은 props 수가 적어 가독성을 해치지 않으며, 코드를 더 간결하게 만듭니다.


176-176: 주석 제거가 적절합니다.

export 문은 자명하므로 주석 제거가 PR 목표와 일치하며 코드 가독성에 부정적 영향을 미치지 않습니다.

src/components/group/GroupActionBottomSheet.tsx (2)

10-17: 주석 제거가 적절합니다.

인터페이스 정의가 명확하고 자기 문서화되어 있습니다. 각 prop의 이름과 타입이 충분히 설명적이므로, 제거된 주석은 중복되었을 가능성이 높습니다. TypeScript의 타입 시스템이 충분한 문서화를 제공하고 있습니다.


19-66: PR 목표에 부합하는 리팩터링입니다.

컴포넌트 구현이 간단명료하며, 핸들러 함수들과 조건부 렌더링 로직이 충분히 자기 설명적입니다. 제거된 주석들은 코드의 명확성에 중요하지 않았던 것으로 판단됩니다. 코드 가독성과 유지보수성에 부정적인 영향은 없습니다.

src/api/record/postVote.ts (1)

8-11: 코드 가독성 개선이 잘 되었습니다!

POST 요청을 여러 줄로 분리한 포맷팅 변경이 코드의 가독성을 향상시켰습니다. 기능적 로직은 그대로 유지되며, TypeScript 타입도 적절하게 지정되어 있습니다.

src/types/record.ts (3)

1-25: 레코드/투표 생성 관련 타입은 시그니처 변경 없이 정리만 된 것으로 보입니다

CreateRecordRequest, CreateRecordData, VoteItem, CreateVoteRequest, CreateVoteData 모두 필드 이름과 타입이 자연스럽고, ai_summary 기준으로도 구조 변경은 없는 것으로 보여 주석 제거로 인한 API 스펙 변경 위험은 없어 보입니다. 이 구간은 그대로 머지해도 무방해 보입니다.


46-60: 레코드/투표 수정 관련 타입도 주석 제거 외에 의미 변화는 없어 보입니다

UpdateRecordRequest/UpdateRecordData/UpdateVoteRequest/UpdateVoteData는 필드 수도 적고 역할도 명확해서, 주석이 제거되어도 혼동 가능성이 거의 없어 보입니다. 타입 시그니처 역시 유지되고 있어 이 부분도 그대로 진행해도 괜찮겠습니다.


62-76: AI 사용량/응답 래퍼 타입 정의도 문제 없으며, 주석 제거 영향 미미해 보입니다

CreateAiReviewData, AiUsageData, ApiResponse<T> 모두 필드명이 역할을 충분히 설명하고 있어, 별도의 주석 없이도 의미 파악이 가능합니다. 기존 공개 타입 시그니처를 그대로 유지하면서 불필요한 주석만 제거한 것으로 보여, 이 구간 역시 안전하게 머지 가능해 보입니다.

src/components/recordwrite/RecordContentSection.tsx (1)

13-13: 좋은 변경입니다!

선택적 prop에 기본값을 제공하는 것은 좋은 패턴입니다.

Also applies to: 19-19

src/pages/pollwrite/PollWrite.tsx (2)

228-249: LGTM!

투표 생성 로직이 정확하며, 포맷팅 변경만 있습니다.


293-293: LGTM!

타이틀 문자열의 따옴표 스타일 변경은 문제없습니다.

Also applies to: 317-317

src/components/pollwrite/PollCreationSection.tsx (1)

20-21: 좋은 변경입니다!

선택적 prop들에 기본값을 제공하는 것은 좋은 패턴이며, RecordContentSection과 일관성 있게 적용되었습니다.

Also applies to: 29-30

src/components/today-words/MessageList/MessageList.tsx (2)

41-43: 상태 동기화 로직이 올바르게 구현되었습니다.

initialMessages prop이 변경될 때마다 로컬 상태를 동기화하는 패턴이 정확합니다.


94-140: 삭제 플로우가 잘 구현되었습니다.

API 호출 후 로컬 상태 업데이트(Line 102), 콜백 실행, 그리고 사용자 피드백(스낵바)이 올바른 순서로 처리되고 있습니다. 에러 처리도 포괄적으로 구현되어 있습니다(API 실패, isSuccess: false 응답, roomId 누락 케이스 모두 처리).

src/api/rooms/deleteDailyGreeting.ts (1)

12-26: LGTM!

주석 제거 후에도 함수 로직과 에러 처리가 올바르게 유지되어 있습니다.

src/components/recordwrite/PageRangeSection.tsx (2)

29-40: LGTM!

인터페이스 정의가 깔끔하게 유지되어 있으며, 주석 제거 후에도 props 타입이 명확합니다.


42-95: LGTM!

입력 검증, 토글 핸들링, 툴팁 상태 관리 로직이 모두 올바르게 유지되어 있습니다.

src/utils/isbn.ts (2)

1-4: LGTM!

normalizeIsbntoUpperCase() 추가가 적절합니다. ISBN-10의 체크 디지트로 'X'가 사용될 수 있으며, isIsbn10 정규식이 대문자 'X'를 기대하므로 정규화 단계에서 대문자 변환이 필요합니다.


6-14: LGTM!

ISBN-10에서 ISBN-13으로의 변환 로직이 EAN-13 체크섬 표준을 올바르게 구현하고 있습니다.

src/types/memory.ts (3)

56-73: LGTM!

Record 인터페이스에 profileImageUrl, isLiked, isLocked 필드가 추가되어 Post 인터페이스와 일관성이 유지됩니다.


75-83: LGTM!

PollOption 인터페이스에 voteItemIdisVoted 필드가 추가되어 투표 기능 구현에 필요한 정보를 제공합니다.


1-7: VoteItem 타입 중복 확인됨 - 정리 필요

현재 코드베이스에 VoteItem 인터페이스가 3개 파일에 서로 다른 형태로 정의되어 있습니다:

  • src/types/memory.ts: {voteItemId, itemName, percentage, count, isVoted}
  • src/types/record.ts: {itemName} (별도로 VoteItemResult 타입 정의됨)
  • src/api/rooms/getRoomPlaying.ts: {itemName}

이는 의도적인 분리(요청/응답, 메모리 vs 레코드 컨텍스트)이거나 타입 중복일 가능성이 있습니다. 다음 중 하나를 검토하세요:

  1. 타입 통합: 공통 기본 타입을 정의하고 필요시 확장
  2. 명확한 네이밍: 목적별로 명확한 이름(예: MemoryVoteItem, RecordVoteItem)으로 구분
  3. 타입 분리 의도 문서화: 각각 다른 용도임을 명시
src/components/memory/UploadProgressBar/UploadProgressBar.tsx (1)

21-33: LGTM!

프로그레스 바 로직이 명확하게 구현되어 있습니다. 주석 제거 후에도 코드 흐름이 이해하기 쉽습니다.

src/types/roomPostLike.ts (1)

1-16: RoomPostLike 관련 타입 정의 유지 상태 양호

요청/응답 인터페이스 구조나 필드 타입이 모두 일관적이고, 주석 제거로 인한 의미 손실도 없어 보입니다. 현재 이름만으로도 역할이 잘 드러나서 타입 정의 그대로 사용해도 무방해 보입니다.

src/api/rooms/leaveRoom.ts (1)

3-19: leaveRoom API 동작 변화 없음, 주석 제거만 진행된 것으로 보임

응답 타입과 삭제 요청 경로, 에러 처리 흐름 모두 기존 패턴과 일관적이며, 주석 제거로 인한 이해도 저하는 없어 보입니다. 이 상태로 유지해도 괜찮겠습니다.

src/api/memory/getMemoryPosts.ts (1)

7-31: 기록장 조회 쿼리 파라미터 구성 로직 적절

type 기본값, sort의 group 타입 한정, pageStart/pageEnd와 boolean 플래그들의 조건부 append 처리까지 모두 안정적으로 보입니다. 주석 없이도 의도가 코드에 잘 드러나서 유지보수에 문제 없을 것 같습니다.

src/api/rooms/createDailyGreeting.ts (1)

3-16: 오늘의 한마디 생성 타입/요청 구조 명확

요청 바디(content)와 응답 래퍼(CreateDailyGreetingResponse) 구조가 단순·일관적이며, 주석 제거로 인해 추가 설명이 꼭 필요해 보이지도 않습니다. 현재 형태로 충분히 자기 설명적인 코드라고 판단됩니다.

src/api/record/deleteRecord.ts (1)

4-22: 기록 삭제 API 타입/에러 처리 모두 기존 패턴과 일관

DeleteRecordDataroomId만 담고, 공통 ApiResponse<DeleteRecordData>를 사용하는 구조가 다른 API들과 잘 맞습니다. try/catch에서 로그 후 재throw 패턴도 동일해 동작 상 문제는 없어 보입니다.

src/components/common/BookSearchBottomSheet/useBookSearch.ts (1)

3-7: 책 검색·페이지네이션 로직이 정리되어 있고 동작도 일관

  • convertToSearchedBooks를 사용해 API 결과를 통일된 SearchedBookBook 형태로 변환하고, 추가 페이지 시 startIndex로 ID를 이어붙이는 방식이 깔끔합니다.
  • performSearch에서 새 검색과 “더 보기”를 isNewSearch로 분리하고, isLoadingMore·hasNextPage 가드로 중복 호출을 막는 흐름도 안정적으로 보입니다.
  • loadMoreSearchResults와 debounce 기반 handleSearchQueryChange 조합 역시 현재 요구사항 범위에서는 충분히 안전해 보여, 주석 제거로 인한 이해도 저하는 없다고 판단됩니다.

Also applies to: 119-178, 195-213, 246-253

src/components/memory/RecordItem/PollRecord.tsx (1)

19-25: 투표 토글 및 상위 동기화 로직이 명확하게 정리됨

  • postId, shouldBlur, onVoteUpdate 추가로 컴포넌트 책임이 더 분명해졌고, shouldBlur일 때 클릭을 막는 처리(가드 + 스타일)도 일관적입니다.
  • e.stopPropagation()으로 투표 클릭 시 상위 카드 클릭 이벤트를 차단한 부분이 UX 측면에서 특히 좋아 보입니다.
  • 응답의 voteItems를 기반으로 percentage, count, isVoted, isHighest를 다시 계산해 currentOptions와 상위 콜백 둘 다 갱신하는 흐름이 자연스럽고, 에러 코드별 메시지 분기와 마지막에 response.message를 사용하는 fallback도 적절합니다.
  • 이 정도 복잡도의 로직은 현재 코드만으로도 충분히 읽히기 때문에, 제거된 주석이 없더라도 이해나 유지보수에 큰 문제는 없을 것으로 보입니다.

Also applies to: 41-68, 74-147, 149-179

src/components/group/HotTopicSection.tsx (1)

39-125: HotTopicSection 드래그/스와이프 로직은 주석 제거 후에도 일관적으로 보입니다.

드래그 상태 관리, translateX 계산, 인덱스 기반 스냅 로직 흐름이 명확하고, containerWidth = 100으로 슬라이드 1칸을 100% 단위로 두는 설계도 기존 퍼센트 기반 이동과 자연스럽게 맞습니다. 비교적 복잡한 부분이지만 함수·변수 이름만으로 의도가 잘 드러나서, 이 파일에서 제거된 주석이 없더라도 유지보수에는 무리가 없어 보입니다.

src/api/record/getAiUsage.ts (1)

4-8: getAiUsage API는 주석/포맷 정리만 있고 동작 변화는 없어 보입니다.

apiClient.get<GetAiUsageResponse>(\/rooms/${roomId}/users/ai-usage`)호출 후response.data`만 반환하는 패턴이 다른 API들과 일관적이고, 한 줄 템플릿 리터럴 정리도 가독성 측면에서 무리 없습니다.

src/api/record/deleteVote.ts (1)

4-18: deleteVote API는 주석 제거 외에는 기존 동작을 잘 유지하고 있습니다.

DeleteVoteDataDeleteVoteResponse가 공통 ApiResponse 패턴과 맞고, try/catch에서 에러를 로그만 남기고 다시 던지는 구조도 호출부 공통 처리에 적합합니다. roomId 용도와 엔드포인트 경로가 코드만으로 충분히 드러나서, 이 부분의 주석 제거는 크게 문제 없다고 판단됩니다.

src/api/rooms/getRoomMembers.ts (1)

48-60: getRoomMembers의 에러 코드(140011) 처리 로직은 주석 없이도 충분히 명확합니다.

AxiosError이면서 error.response?.data?.code === 140011일 때만 '방 접근 권한이 없습니다.'라는 새 Error를 던지고, 나머지는 원본 에러를 그대로 재던져 호출부에서 구분할 수 있게 되어 있습니다. 도메인 코드와 메시지가 구체적이라, 여기에 붙어 있던 설명 주석은 없어도 유지보수에 큰 영향은 없을 것 같습니다.

src/types/room.ts (1)

49-62: Room 관련 타입 확장은 자연스럽지만, RoomMember.joinedAt 필수 여부는 한 번 확인해 주세요.

RoomMemberprofileImageUrl?: stringjoinedAt: string이 추가되고, ApiResponse<T>messagedata가 포함된 구조는 현재 여러 API 응답에서 사용하는 패턴과 잘 맞는 것 같습니다.

다만 joinedAt을 필수(string)로 두면, 일부 오래된 방이나 테스트 환경에서 해당 필드가 누락된 응답이 들어올 경우 런타임에서 undefined를 문자열로 가정하게 될 수 있습니다.

  • 백엔드 스키마상 항상 내려오는 필드라면 지금처럼 필수로 두는 것이 맞고,
  • 선택적으로만 내려온다면 joinedAt?: string으로 조정하는 편이 안전합니다.

한 번 실제 응답 스키마와 맞는지만 확인해 주시면 좋겠습니다.

src/api/images/uploadImage.ts (1)

7-12: UploadImageResponse의 data를 optional로 둔 변경이 다중 업로드 로직과 잘 맞습니다.

UploadImageResponsedata?: UploadImageData 선언과, uploadMultipleImages에서 value.isSuccess && value.data?.imageUrl로 방어적으로 접근하는 코드가 서로 일관적입니다. 일부 실패/에러 응답에서 data가 없을 수 있는 상황까지 타입으로 표현한 것이어서, 주석 제거와 함께 타입 정의도 실제 사용 패턴에 더 잘 맞게 정리된 것으로 보입니다.

Also applies to: 43-85

src/api/record/pinRecordToFeed.ts (1)

15-15: 변경사항 확인 완료

주석 제거 및 trailing comma 추가로 코드 일관성이 개선되었습니다. 기능적 변경사항이 없어 안전합니다.

src/api/rooms/getDailyGreeting.ts (1)

20-34: 포맷팅 개선 확인

파라미터 destructuring을 multiline 형식으로 변경하여 가독성이 개선되었습니다. 기능적 변경사항이 없습니다.

src/components/common/BookSearchBottomSheet/BookSearchBottomSheet.tsx (2)

54-64: body scroll 관리 개선

useEffect cleanup이 제대로 추가되어 컴포넌트 언마운트 시 body overflow 속성이 올바르게 복원됩니다. 이는 메모리 누수를 방지하고 사용자 경험을 개선합니다.


129-136: BookList 컴포넌트 props 전달 개선

isLoadingMoreisSearchMode props가 추가되어 로딩 상태 및 검색 모드를 BookList에서 활용할 수 있게 되었습니다. UI 일관성 향상에 기여합니다.

src/api/feeds/createFeed.ts (1)

28-31: 함수 시그니처 간소화

함수 시그니처를 single-line으로 변경하여 코드가 더 간결해졌습니다. 기능적 변경사항은 없습니다.

src/hooks/useCreateFeed.ts (1)

15-154: Snackbar UI 일관성 개선

모든 openSnackbar 호출에 variant: 'top'onClose: closePopup을 추가하여 사용자 경험의 일관성이 향상되었습니다. 검증 로직은 그대로 유지되어 안전합니다.

src/components/memory/RecordItem/RecordItem.tsx (3)

251-295: 클릭 핸들러 로직 통합

handleClick 함수가 통합되어 코드 중복이 제거되고 가독성이 개선되었습니다. shouldBlur 상태에서의 early return으로 조건부 로직이 명확해졌습니다.


335-342: PollRecord의 onVoteUpdate 비활성화

onVoteUpdate가 빈 함수로 변경되어 투표 업데이트 시 외부 상태 변경이 발생하지 않습니다. 이것이 의도된 동작인지 확인이 필요합니다. 투표 후 UI 업데이트가 제대로 작동하는지 테스트하세요.


105-122: Poll 옵션 파라미터 파싱은 올바르게 구현되어 있습니다.

검증 결과, RecordItem.tsx에서 전송한 options 파라미터는 PollWrite.tsx에서 다음과 같이 올바르게 처리되고 있습니다:

  • 전송: RecordItem.tsx 110줄에서 JSON.stringify(pollOptions?.map(option => option.text) || [])로 직렬화
  • 수신: PollWrite.tsx 52줄에서 searchParams.get('options')로 파라미터 추출
  • 파싱: PollWrite.tsx 68줄에서 JSON.parse(decodeURIComponent(existingOptions))로 역직렬화
  • 에러 처리: 70-71줄에서 파싱 실패 시 예외 처리 및 로깅 (console.error)

URLSearchParams는 자동으로 값을 인코딩/디코딩하므로 양방향 변환이 정상적으로 작동합니다.

src/pages/memory/Memory.tsx (3)

93-148: 데이터 로딩 로직 유지

loadMemoryPosts 함수의 핵심 로직이 유지되어 기능이 보존되었습니다. 에러 처리와 필터링 로직도 그대로 작동합니다.


141-143: 에러 처리 후 early return 추가

Line 141-142에서 총평 조회 권한이 없을 때 setActiveFilter(null)을 호출하고 early return을 추가한 것은 올바른 에러 처리입니다. 불필요한 에러 메시지 설정을 방지합니다.


208-232: 메모이제이션된 필터링 로직

useMemo를 사용한 currentRecords, sortedRecords, filteredRecords 계산 로직이 유지되어 성능이 보장됩니다. 필터링 조건이 명확하게 구현되어 있습니다.

src/pages/groupDetail/ParticipatedGroupDetail.tsx (1)

78-157: 주석 제거가 적절합니다.

주석 제거가 깔끔하게 이루어졌으며, 모든 기능 로직은 그대로 유지되고 있습니다.

src/pages/post/UpdatePost.tsx (1)

38-116: 코드 정리가 적절합니다.

console.log 및 주석 제거로 코드 가독성이 향상되었으며, 핵심 로직은 모두 유지되고 있습니다.

src/pages/group/CreateGroup.tsx (3)

10-10: import 경로 수정이 적절합니다.

이중 슬래시를 제거하여 올바른 import 경로로 수정되었습니다.


83-83: 중복 제출 방지 로직이 잘 추가되었습니다.

isSubmitting 체크로 중복 제출을 방지하는 가드가 적절하게 추가되었습니다.


187-189: 비밀번호 유효성 검사가 적절합니다.

4자리 숫자 비밀번호 검증 로직(/^\d{4}$/)이 올바르게 구현되어 있습니다.

src/pages/post/CreatePost.tsx (2)

24-24: ensureIsbn13 사용이 적절합니다.

ISBN 유효성 검사 및 정규화 로직을 유틸리티 함수로 중앙화하여 코드 재사용성이 향상되었습니다.


76-79: onSuccess 콜백 시그니처 변경이 일관적입니다.

useCreateFeed 훅의 변경사항과 일치하도록 onSuccess 콜백이 매개변수 없이 호출되도록 업데이트되었습니다. 네비게이션 로직은 콜백 내부에서 적절하게 처리되고 있습니다.

src/pages/today-words/TodayWords.tsx (1)

193-199: 무한 스크롤 조건 로직은 의도대로 잘 동작해 보입니다

scrollHeight - 100 여유를 두고, !isLoadingMore && !isLast && hasInitiallyLoaded를 함께 체크하는 조건은 과도한 호출을 막으면서도 UX 측면에서 자연스러운 트리거 포인트로 보입니다. 별도 이슈는 없어 보입니다.

Comment on lines 15 to 26
const PasswordInputSection = ({ password, onPasswordChange }: PasswordInputSectionProps) => {
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// 숫자만 허용하고 최대 4자리까지만 입력 가능
const numericValue = value.replace(/[^0-9]/g, '');
if (numericValue.length <= 4) {
onPasswordChange(numericValue);
}
};

const handleClose = () => {
onPasswordChange(''); // 입력된 숫자 전체 삭제
onPasswordChange('');
};
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

미사용 prop을 호출해야 합니다.

onClose prop이 정의되어 있지만 handleClose 함수에서 호출되지 않습니다. 부모 컴포넌트에 닫기 이벤트를 알리기 위해 onClose를 호출해야 할 것으로 보입니다.

다음 diff를 적용하여 수정하세요:

-const PasswordInputSection = ({ password, onPasswordChange }: PasswordInputSectionProps) => {
+const PasswordInputSection = ({ password, onPasswordChange, onClose }: PasswordInputSectionProps) => {
   const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
     const value = e.target.value;
     const numericValue = value.replace(/[^0-9]/g, '');
     if (numericValue.length <= 4) {
       onPasswordChange(numericValue);
     }
   };

   const handleClose = () => {
     onPasswordChange('');
+    onClose();
   };
📝 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
const PasswordInputSection = ({ password, onPasswordChange }: PasswordInputSectionProps) => {
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// 숫자만 허용하고 최대 4자리까지만 입력 가능
const numericValue = value.replace(/[^0-9]/g, '');
if (numericValue.length <= 4) {
onPasswordChange(numericValue);
}
};
const handleClose = () => {
onPasswordChange(''); // 입력된 숫자 전체 삭제
onPasswordChange('');
};
const PasswordInputSection = ({ password, onPasswordChange, onClose }: PasswordInputSectionProps) => {
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
const numericValue = value.replace(/[^0-9]/g, '');
if (numericValue.length <= 4) {
onPasswordChange(numericValue);
}
};
const handleClose = () => {
onPasswordChange('');
onClose();
};
🤖 Prompt for AI Agents
In src/components/creategroup/PrivacySettingSection/PasswordInputSection.tsx
around lines 15 to 26, the component defines a handleClose that clears the
password but does not call the onClose prop; update the component props to
accept onClose (if not already typed) and invoke onClose() inside handleClose
after calling onPasswordChange('') so the parent is notified when the input is
closed/cleared; ensure types are updated (PasswordInputSectionProps) and any
usages are adjusted accordingly.

Comment on lines +82 to +158
const loadMessages = useCallback(
async (cursor?: string, isRefresh = false) => {
if (!roomId) return;

try {
if (isRefresh) {
setIsLoading(true);
} else {
setIsLoadingMore(true);
}
try {
if (isRefresh) {
setIsLoading(true);
} else {
setIsLoadingMore(true);
}

const response = await getDailyGreeting({
roomId: parseInt(roomId),
cursor: cursor || undefined,
});
const response = await getDailyGreeting({
roomId: parseInt(roomId),
cursor: cursor || undefined,
});

if (response.isSuccess) {
const newMessages = response.data.todayCommentList.map(convertToMessage);

if (isRefresh) {
setMessages(newMessages);
if (response.isSuccess) {
const newMessages = response.data.todayCommentList.map(convertToMessage);

if (isRefresh) {
setMessages(newMessages);
} else {
setMessages(prev => [...prev, ...newMessages]);
}

setNextCursor(response.data.nextCursor);
setIsLast(response.data.isLast);
setHasInitiallyLoaded(true);

if (isRefresh) {
setTimeout(() => {
window.scrollTo({ top: document.body.scrollHeight, behavior: 'auto' });
}, 100);
}
} else {
setMessages(prev => [...prev, ...newMessages]);
openSnackbar({
message: response.message || '오늘의 한마디 목록을 불러오는데 실패했습니다.',
variant: 'top',
onClose: () => {},
});
}

setNextCursor(response.data.nextCursor);
setIsLast(response.data.isLast);
setHasInitiallyLoaded(true);

// 초기 로딩 시 스크롤을 맨 아래로 이동
if (isRefresh) {
setTimeout(() => {
window.scrollTo({ top: document.body.scrollHeight, behavior: 'auto' });
}, 100);
} catch (error) {
console.error('오늘의 한마디 목록 조회 오류:', error);

let errorMessage = '오늘의 한마디 목록을 불러오는 중 오류가 발생했습니다.';

if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as {
response?: {
data?: {
message?: string;
code?: number;
};
};
};

if (axiosError.response?.data?.message) {
errorMessage = axiosError.response.data.message;
} else if (axiosError.response?.data?.code === 403) {
errorMessage = '방 접근 권한이 없습니다.';
} else if (axiosError.response?.data?.code === 404) {
errorMessage = '존재하지 않는 방입니다.';
}
}
} else {

openSnackbar({
message: response.message || '오늘의 한마디 목록을 불러오는데 실패했습니다.',
message: errorMessage,
variant: 'top',
onClose: () => {},
});
} finally {
setIsLoading(false);
setIsLoadingMore(false);
}
} catch (error) {
console.error('오늘의 한마디 목록 조회 오류:', error);

let errorMessage = '오늘의 한마디 목록을 불러오는 중 오류가 발생했습니다.';

if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as {
response?: {
data?: {
message?: string;
code?: number;
};
};
};

if (axiosError.response?.data?.message) {
errorMessage = axiosError.response.data.message;
} else if (axiosError.response?.data?.code === 403) {
errorMessage = '방 접근 권한이 없습니다.';
} else if (axiosError.response?.data?.code === 404) {
errorMessage = '존재하지 않는 방입니다.';
}
}

openSnackbar({
message: errorMessage,
variant: 'top',
onClose: () => {},
});
} finally {
setIsLoading(false);
setIsLoadingMore(false);
}
}, [roomId, convertToMessage, openSnackbar]);
},
[roomId, convertToMessage, openSnackbar],
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

loadMessagesuseEffect 의존성으로 인해 불필요한 중복 호출/재시도 루프가 발생할 수 있습니다

현재 구조에서는 다음 문제가 생길 수 있습니다.

  • loadMessagesuseCallback으로 감싸되어 있지만, 의존성 배열에 들어있는 convertToMessage는 일반 함수라 렌더마다 새로 생성됩니다.
  • 그 결과 loadMessages도 매 렌더마다 새로 만들어지고, useEffect(184-188)가 loadMessages를 의존성에 포함하고 있어, roomId && !hasInitiallyLoaded 조건이 유지되는 동안 효과가 반복 실행될 수 있습니다.
    • 최초 진입 시: 동일 요청이 2번 이상 호출될 수 있습니다.
    • 특히 API 실패로 hasInitiallyLoadedtrue로 세팅되지 않는 경우, 렌더가 반복되는 동안 같은 요청을 잦은 간격으로 재시도하는 루프가 생길 여지가 있습니다.

convertToMessage 자체는 외부 상태를 참조하지 않으므로, useCallback으로 한 번 래핑해 참조를 안정화하는 편이 안전해 보입니다.

예시 수정안:

-  const convertToMessage = (item: TodayCommentItem): Message => {
-    const timeAgo = item.postDate || '방금 전';
-
-    const createdAt = new Date();
-
-    return {
-      id: item.attendanceCheckId.toString(),
-      user: item.creatorNickname,
-      content: item.todayComment,
-      timestamp: item.date,
-      timeAgo,
-      createdAt,
-      profileImageUrl: item.creatorProfileImageUrl,
-      isWriter: item.isWriter,
-    };
-  };
+  const convertToMessage = useCallback(
+    (item: TodayCommentItem): Message => {
+      const timeAgo = item.postDate || '방금 전';
+      const createdAt = new Date();
+
+      return {
+        id: item.attendanceCheckId.toString(),
+        user: item.creatorNickname,
+        content: item.todayComment,
+        timestamp: item.date,
+        timeAgo,
+        createdAt,
+        profileImageUrl: item.creatorProfileImageUrl,
+        isWriter: item.isWriter,
+      };
+    },
+    [],
+  );

이렇게 하면:

  • convertToMessage 참조가 안정화되고,
  • loadMessagesroomId/openSnackbar가 바뀌지 않는 한 동일 참조를 유지하게 되어,
  • 초기 로드/실패 상황에서도 불필요한 중복 호출과 잠재적인 반복 재시도를 막을 수 있습니다.

Committable suggestion skipped: line range outside the PR's diff.

@ljh130334 ljh130334 merged commit 7b3d12f into THIP-386 Nov 26, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants