Skip to content

[FIX] 9월 3주차 QA 사항 - 지현#256

Merged
ljh130334 merged 9 commits intodevelopfrom
bugfix/jihyeon
Sep 26, 2025
Merged

[FIX] 9월 3주차 QA 사항 - 지현#256
ljh130334 merged 9 commits intodevelopfrom
bugfix/jihyeon

Conversation

@ljh130334
Copy link
Member

@ljh130334 ljh130334 commented Sep 23, 2025

#️⃣ 연관된 이슈

#250

📝 작업 내용

  • 모달창 '아니요' 버튼 동작하도록 수정
  • 완료된 모임방 기록 좋아요, 댓글 작성 서버 에러 메시지를 스낵바로 표시하도록 수정 → 댓글 작성 부분은 messagebox 자체를 삭제하면서 쓸모없어지게 됨..
  • 완료된 모임방 상세 페이지 케밥 버튼, 오늘의 한마디 messagebox, 댓글 messagebox, Fab 버튼 숨김 처리

💬 리뷰 요구사항(선택)

  • 테스트 데이터를 넣어서 작업을 진행하여 실제 서버랑 어떻게 상호작용하는지 한 번 더 확인이 필요합니다.

Summary by CodeRabbit

  • 신기능
    • 방 완료 판정(isRoomCompleted) 도입으로 댓글 입력창·컨텐츠 추가 버튼·그룹 상세 더보기 버튼 등 자동으로 숨김 처리.
    • 페이지 접근 시 URL 파라미터 기반 필터 적용(페이징·필터 초기화).
  • 버그 수정
    • 좋아요·답글·투표·핀 API 응답의 성공 여부를 기준으로 UI 반영해 안정성 향상.
    • 서버/네트워크 오류 시 사용자에게 스낵바로 명확한 메시지 표시.
  • 개선
    • 팝업 닫기 흐름 중앙화(onClose 전달) 및 터치·드래그 감지로 투표 오작동 방지.

@ljh130334 ljh130334 self-assigned this Sep 23, 2025
@ljh130334 ljh130334 added 🐞 BugFix Something isn't working ✨ Feature 기능 개발 labels Sep 23, 2025
@vercel
Copy link

vercel bot commented Sep 23, 2025

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

Project Deployment Preview Comments Updated (UTC)
thip Ready Ready Preview Comment Sep 26, 2025 5:57am

@coderabbitai
Copy link

coderabbitai bot commented Sep 23, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

방 완료 상태 판정(isRoomCompleted) 유틸 추가 및 여러 컴포넌트에서 방 진행 상태를 조회해 입력/추가 UI를 숨기도록 변경했고, 팝업 렌더 시 ConfirmModal/MoreMenu에 중앙화된 onClose를 전달하며 댓글·기록·투표 관련 API 오류 처리를 일관화했습니다.

Changes

Cohort / File(s) Summary
Room 상태 유틸 및 UI 게이트
src/utils/roomStatus.ts, src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx, src/pages/memory/Memory.tsx, src/pages/today-words/TodayWords.tsx, src/pages/groupDetail/ParticipatedGroupDetail.tsx
isRoomCompleted 유틸 추가. getRoomPlaying 호출로 roomCompleted 상태 도입, 완료된 방에서는 MessageInput, MemoryAddButton, 더보기 버튼 등 입력/추가 UI를 숨김. GlobalCommentBottomSheet는 열릴 때 상태 조회 및 입력 숨김 처리 추가.
팝업 onClose 전달 및 props 연계
src/components/common/Modal/PopupContainer.tsx, 관련 ConfirmModal/MoreMenu
PopupContainer가 ConfirmModal과 MoreMenu 렌더 시 onClose={closePopup} 전달하도록 변경(모달 props에 onClose 연계).
댓글·서브댓글/댓글창 에러 처리 정비
src/components/common/Post/Reply.tsx, src/components/common/Post/SubReply.tsx, src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx, src/api/comments/postReply.ts, src/api/comments/postLike.ts
API 응답의 isSuccess/message 기반으로 UI 업데이트를 가드하고, 실패 시 서버 메시지를 스낵바로 노출. postReply/postLike에 try/catch 추가해 서버 에러 응답을 반환하거나 재던짐.
레코드·투표 처리 및 리팩터링
src/components/memory/RecordItem/RecordItem.tsx, src/components/memory/RecordItem/PollRecord.tsx, src/api/record/postVote.ts
더보기/핀 흐름 간소화(인라인 호출), 서버 메시지 우선 사용으로 에러 경로 변경, IntersectionObserver 참조 안전성 개선, 특정 에러코드 분기 제거. postVote에 try/catch 추가.
룸 게시물 좋아요 API 에러 처리 보강
src/api/roomPosts/postRoomPostLike.ts
try/catch 추가, 에러 시 error.response.data 반환(없으면 예외 재발생) 및 로깅 보강.
터치/드래그 투표 및 HotTopic 변경
src/components/group/HotTopicSection.tsx
헤더 클릭 API 제거(onClick optional), 드래그/터치 이동 감지(hasMoved) 추가, 투표 클릭 시 드래그 여부로 동작 제어 및 터치 핸들러 추가. Props 서명 변경.
헤더/버튼 인터랙션 조정
src/components/common/TitleHeader.tsx, src/pages/groupDetail/ParticipatedGroupDetail.tsx
Right 버튼 클릭 핸들러를 isNextActive 조건으로만 전달해 비활성 시 클릭 불가 처리. 그룹 상세에서 완료된 방에 더보기 버튼 숨김.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Page/Component
  participant API as getRoomPlaying
  participant Util as isRoomCompleted

  UI->>API: fetch room playing status (roomId)
  API-->>UI: { progressEndDate, ... }
  UI->>Util: isRoomCompleted(progressEndDate)
  Util-->>UI: true/false

  alt roomCompleted == true
    UI-->>UI: 입력/추가 UI 숨김 (MessageInput, MemoryAddButton, more 버튼)
  else roomCompleted == false
    UI-->>UI: 입력/추가 UI 표시
  end
Loading
sequenceDiagram
  autonumber
  participant User as User
  participant Popup as PopupContainer
  participant Modal as ConfirmModal/MoreMenu

  User->>Popup: open popup
  Popup->>Modal: render with onClose = closePopup
  User->>Modal: trigger close
  Modal-->>Popup: call onClose()
  Popup-->>Popup: closePopup() 실행
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

깡총깡총, 당근 코드 물고왔네 🥕🐇
방이 끝나면 입력창은 조용히 눈을 감고,
팝업엔 문닫이 달려 중앙으로 왈칵 닫히네.
에러는 스낵바로 속삭여 주고, 투표는 드래그와 장난질 피하네.
토끼가 외쳐요 — 리팩터 한 입, 버그는 달아나!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title Check ❓ Inconclusive 제목이 “9월 3주차 QA 사항”처럼 QA 항목 전반을 포괄하는 모호한 표현을 사용하여 실제로 어떤 주요 변경이 이루어졌는지 파악하기 어렵습니다. PR의 핵심 변경사항을 반영하여 “완료된 모임방에서 오류 메시지 스낵바 표시 및 UI 요소 숨김 처리”와 같이 구체적이고 간결한 제목으로 수정해 주세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

📜 Recent 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 abd1816 and 190e45d.

📒 Files selected for processing (1)
  • src/pages/memory/Memory.tsx (6 hunks)

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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/components/memory/RecordItem/RecordItem.tsx (2)

139-141: roomId 없음 시 삭제 API가 방 ID 1에 호출될 위험

roomId || '1' 기본값은 잘못된 방에 삭제를 발생시킬 수 있습니다. 없으면 즉시 중단하고 사용자에게 안내하세요.

-    const currentRoomId = roomId || '1';
+    if (!roomId) {
+      openSnackbar({ message: '방 정보를 찾을 수 없습니다.', variant: 'top', onClose: () => {} });
+      return;
+    }
+    const currentRoomId = roomId;

199-201: roomId 없을 때 API 호출 차단 — delete / pin 핸들러 방어 로직 추가

roomId || '1' 기본값은 잘못된 room(1)으로 API가 호출될 수 있으니 delete/pin 핸들러에서 roomId 없으면 스낵바 노출 후 즉시 반환하도록 수정하세요.

  • 수정 대상: src/components/memory/RecordItem/RecordItem.tsx — handleDelete (currentRoomId: line 139), handlePinRecord (currentRoomId: line 199)
  • 참고(확인 필요): src/components/memory/MemoryAddButton/MemoryAddButton.tsx — navigate 기본값 '1' 사용 (lines 39, 49)
-    const currentRoomId = roomId || '1';
+    if (!roomId) {
+      openSnackbar({ message: '방 정보를 찾을 수 없습니다.', variant: 'top', onClose: () => {} });
+      return;
+    }
+    const currentRoomId = roomId;
🧹 Nitpick comments (10)
src/components/memory/RecordItem/PollRecord.tsx (1)

92-105: 최대값 계산 중복(O(n^2)) 및 빈 배열 시 -Infinity 엣지케이스

Math.max(...arr)를 매 항목마다 계산하면 불필요합니다. 사전에 maxCount 한 번 계산하고, 빈 배열일 때 0으로 방어하세요.

-        const updatedOptions = currentOptions.map(opt => {
-          const updatedItem = response.data.voteItems.find(
-            item => item.voteItemId === opt.voteItemId,
-          );
+        const voteItems = response.data.voteItems ?? [];
+        const maxCount = Math.max(0, ...voteItems.map(item => item.count));
+        const updatedOptions = currentOptions.map(opt => {
+          const updatedItem = voteItems.find(item => item.voteItemId === opt.voteItemId);
           if (updatedItem) {
             return {
               ...opt,
               percentage: updatedItem.percentage,
               count: updatedItem.count,
               isVoted: updatedItem.isVoted,
-              isHighest:
-                updatedItem.count === Math.max(...response.data.voteItems.map(item => item.count)),
+              isHighest: updatedItem.count === maxCount,
             };
           }
           return opt;
         });
src/components/memory/RecordItem/RecordItem.tsx (1)

79-79: 좋아요 카운트 음수 방지

동기화 이슈 등으로 0에서 감소할 가능성 방어 차원에서 하한을 두는 편이 안전합니다.

-        setCurrentLikeCount((prev: number) => (response.data.isLiked ? prev + 1 : prev - 1));
+        setCurrentLikeCount((prev: number) =>
+          Math.max(0, response.data.isLiked ? prev + 1 : prev - 1),
+        );
src/pages/groupDetail/ParticipatedGroupDetail.tsx (1)

247-256: 완료 전/후 상태 전환 시 열려있는 바텀시트 자동 닫기

방이 완료 상태로 전환될 때 이미 열린 더보기 바텀시트를 자동으로 닫아 UX/행위 차단을 명확히 하세요.

   // 모임방 완료 여부 확인
   const isCompleted = roomData ? isRoomCompleted(roomData.data.progressEndDate) : false;
 
+  // 완료로 전환되면 바텀시트 닫기
+  useEffect(() => {
+    if (isCompleted && isBottomSheetOpen) {
+      setIsBottomSheetOpen(false);
+    }
+  }, [isCompleted, isBottomSheetOpen]);
src/pages/today-words/TodayWords.tsx (2)

174-191: 접근 권한 없음(140011)일 때 그룹 홈으로 리다이렉트 권장

getRoomPlaying이 권한 오류 시 Error를 던지므로 동일 UX로 이동 처리하면 일관성이 좋아집니다.

   useEffect(() => {
     const checkRoomStatus = async () => {
       if (!roomId) return;
 
       try {
         const response = await getRoomPlaying(parseInt(roomId));
         if (response.isSuccess) {
           const completed = isRoomCompleted(response.data.progressEndDate);
           setRoomCompleted(completed);
         }
-        }
+        }
       } catch (error) {
-        console.error('모임방 상태 확인 오류:', error);
+        console.error('모임방 상태 확인 오류:', error);
+        if (error instanceof Error && error.message === '방 접근 권한이 없습니다.') {
+          navigate('/group', { replace: true });
+        }
       }
     };
 
     checkRoomStatus();
   }, [roomId]);

215-227: 백엔드 상태 변화 대비: 전송 핸들러에서도 완료 상태 가드

UI에서 입력을 숨기지만, 상태 경쟁이나 개발자 도구로의 호출을 고려해 핸들러에서도 한 번 더 차단하세요.

   const handleSendMessage = useCallback(async () => {
-    if (inputValue.trim() === '' || isSubmitting) return;
+    if (inputValue.trim() === '' || isSubmitting) return;
+    if (roomCompleted) {
+      openSnackbar({
+        message: '이미 완료된 모임방에서는 작성할 수 없습니다.',
+        variant: 'top',
+        onClose: () => {},
+      });
+      return;
+    }
 
     // roomId가 없으면 에러 처리
     if (!roomId) {
src/pages/memory/Memory.tsx (2)

72-74: 초기값 false로 인한 잠깐 노출(flicker) 가능성 — 완료 방에서 FAB가 순간 보일 수 있음

상태 로딩 전에 안전하게 숨기려면 tri-state(null|boolean)로 전환하고, 명시적으로 false일 때만 노출하세요.

적용 diff:

-  const [roomCompleted, setRoomCompleted] = useState(false);
+  const [roomCompleted, setRoomCompleted] = useState<boolean | null>(null);
...
-      {!roomCompleted && (
+      {roomCompleted === false && (
         <FloatingElements>
           <MemoryAddButton />
         </FloatingElements>
       )}

Also applies to: 319-323


154-172: 비동기 상태 업데이트 안전성 + parseInt radix 지정

언마운트/roomId 변경 중 setState 경합을 방지하고, parseInt에 기수(10)를 명시하세요.

적용 diff:

-  useEffect(() => {
-    const checkRoomStatus = async () => {
+  useEffect(() => {
+    let isActive = true;
+    const checkRoomStatus = async () => {
       if (!roomId) return;
 
       try {
-        const response = await getRoomPlaying(parseInt(roomId));
+        const response = await getRoomPlaying(parseInt(roomId, 10));
         if (response.isSuccess) {
           const completed = isRoomCompleted(response.data.progressEndDate);
-          setRoomCompleted(completed);
+          if (isActive) setRoomCompleted(completed);
         }
       } catch (error) {
         console.error('모임방 상태 확인 오류:', error);
       }
     };
 
     checkRoomStatus();
-  }, [roomId]);
+    return () => {
+      isActive = false;
+    };
+  }, [roomId]);

추가 제안: 동일 로직이 여러 컴포넌트에서 반복됩니다. useRoomCompleted(roomId) 훅으로 공통화하여 중복 호출/상태 불일치를 줄이길 권장합니다.

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

31-31: 초기값 false로 인한 잠깐 노출(flicker) — 완료 방에서 입력 영역이 순간 보일 수 있음

tri-state(null|boolean)로 전환해 로딩 중에는 입력 영역을 숨기도록 하세요.

적용 diff:

-  const [roomCompleted, setRoomCompleted] = useState(false);
+  const [roomCompleted, setRoomCompleted] = useState<boolean | null>(null);
...
-        {!roomCompleted && (
+        {roomCompleted === false && (
           <InputSection>
             <MessageInput
               placeholder={
                 isReplying ? `@${nickname}님에게 답글을 남겨보세요` : '댓글을 남겨보세요'
               }
               value={inputValue}
               onChange={setInputValue}
               onSend={handleSendComment}
               isReplying={isReplying}
               onCancelReply={handleCancelReply}
               nickname={nickname}
               disabled={isSending}
             />
           </InputSection>
         )}

Also applies to: 167-182


110-130: 비동기 안전성 + parseInt radix 지정

언마운트/닫힘(isOpen=false) 타이밍에 대비해 안전 가드와 radix(10) 명시가 필요합니다.

적용 diff:

-  useEffect(() => {
-    const checkRoomStatus = async () => {
+  useEffect(() => {
+    let isActive = true;
+    const checkRoomStatus = async () => {
       if (!roomId) return;
 
       try {
-        const response = await getRoomPlaying(parseInt(roomId));
+        const response = await getRoomPlaying(parseInt(roomId, 10));
         if (response.isSuccess) {
           const completed = isRoomCompleted(response.data.progressEndDate);
-          setRoomCompleted(completed);
+          if (isOpen && isActive) setRoomCompleted(completed);
         }
       } catch (error) {
         console.error('모임방 상태 확인 오류:', error);
       }
     };
 
     if (isOpen) {
       checkRoomStatus();
     }
-  }, [isOpen, roomId]);
+    return () => { isActive = false; };
+  }, [isOpen, roomId]);

58-96: 댓글 전송 로직 중복 — 훅으로 일원화 제안

useReplyActions.submitComment와 유사 로직이 여기 재구현되어 유지보수 비용이 증가합니다. 훅에 onError/onSuccess 콜백을 받아 스낵바만 외부에서 주입하도록 확장하거나, 공용 유틸로 추출하세요.

원하시면 useRoomCompleted 훅과 함께 submitComment 콜백 확장안까지 패치 제안 드리겠습니다.

📜 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 50ec1d7 and 0c2593b.

📒 Files selected for processing (8)
  • src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (5 hunks)
  • src/components/common/Modal/PopupContainer.tsx (1 hunks)
  • src/components/memory/RecordItem/PollRecord.tsx (5 hunks)
  • src/components/memory/RecordItem/RecordItem.tsx (3 hunks)
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx (2 hunks)
  • src/pages/memory/Memory.tsx (4 hunks)
  • src/pages/today-words/TodayWords.tsx (4 hunks)
  • src/utils/roomStatus.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/pages/today-words/TodayWords.tsx (2)
src/api/rooms/getRoomPlaying.ts (1)
  • getRoomPlaying (65-79)
src/utils/roomStatus.ts (1)
  • isRoomCompleted (10-24)
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (8)
src/stores/useCommentBottomSheetStore.ts (1)
  • useCommentBottomSheetStore (14-26)
src/api/comments/getComments.ts (1)
  • CommentData (3-16)
src/hooks/useReplyActions.ts (1)
  • useReplyActions (10-54)
src/stores/useReplyStore.ts (1)
  • useReplyStore (15-28)
src/hooks/usePopupActions.ts (1)
  • usePopupActions (9-35)
src/api/rooms/getRoomPlaying.ts (1)
  • getRoomPlaying (65-79)
src/utils/roomStatus.ts (1)
  • isRoomCompleted (10-24)
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.styled.ts (1)
  • InputSection (65-70)
src/pages/groupDetail/ParticipatedGroupDetail.tsx (3)
src/utils/roomStatus.ts (1)
  • isRoomCompleted (10-24)
src/pages/groupDetail/ParticipatedGroupDetail.styled.ts (1)
  • ParticipatedWrapper (4-16)
src/pages/groupDetail/GroupDetail.styled.ts (2)
  • TopBackground (20-29)
  • Header (31-50)
src/components/common/Modal/PopupContainer.tsx (1)
src/stores/usePopupStore.ts (2)
  • ConfirmModalProps (12-17)
  • MoreMenuProps (19-27)
src/pages/memory/Memory.tsx (3)
src/api/rooms/getRoomPlaying.ts (1)
  • getRoomPlaying (65-79)
src/utils/roomStatus.ts (1)
  • isRoomCompleted (10-24)
src/pages/memory/Memory.styled.ts (1)
  • FloatingElements (48-58)
src/components/memory/RecordItem/PollRecord.tsx (1)
src/components/memory/RecordItem/PollRecord.styled.ts (2)
  • PollNumber (44-51)
  • PollText (53-60)
🔇 Additional comments (8)
src/utils/roomStatus.ts (1)

13-23: 날짜 파싱 안정화(브라우저 간 파싱 차이/타임존 엣지 케이스 방어 필요)

new Date('YYYY-MM-DD')는 환경에 따라 UTC/로컬 해석이 달라질 수 있습니다. 정규식으로 연/월/일을 추출해 로컬 타임존의 자정/자정-1ms로 직접 구성하면 안전합니다.
[ suggest_recommended_refactor ]

-  // 날짜 형식 정규화 (YYYY.MM.DD -> YYYY-MM-DD)
-  const normalizedDate = progressEndDate.replace(/\./g, '-');
-
-  const endDate = new Date(normalizedDate);
-  const today = new Date();
-
-  // 시간 부분을 제거하고 날짜만 비교
-  today.setHours(0, 0, 0, 0);
-  endDate.setHours(23, 59, 59, 999);
-
-  return today > endDate;
+  // 입력 정규화 및 안전한 파싱 (YYYY.MM.DD / YYYY-MM-DD / YYYY/MM/DD 지원)
+  const trimmed = progressEndDate.trim();
+  const m = trimmed.match(/^(\d{4})[.\-/](\d{1,2})[.\-/](\d{1,2})$/);
+  if (!m) return false;
+  const [, y, mo, d] = m;
+
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+
+  // 로컬 타임존 기준 해당 일의 23:59:59.999로 설정
+  const endDate = new Date(Number(y), Number(mo) - 1, Number(d), 23, 59, 59, 999);
+  return today > endDate;
src/components/common/Modal/PopupContainer.tsx (1)

45-46: ConfirmModal/MoreMenu에 onClose 전달한 변경 좋습니다

팝업 종료 경로를 통일해 회귀 버그를 줄일 수 있습니다. 두 컴포넌트 내부에서 ‘아니요/닫기/바깥 클릭/ESC’ 모두 onClose로 귀결되는지 한 번만 확인 부탁드립니다.

테스트 제안: ConfirmModal과 MoreMenu에서 onClose 핸들러가 실제로 호출되는지 스냅샷/유닛 테스트 또는 E2E에서 확인해 주세요.

Also applies to: 49-49

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

168-170: 잘못된 지적 — PollOption.id가 정의되어 있어 key={option.id}는 유효함

src/types/memory.ts에서 PollOption 인터페이스에 id: string이 정의되어 있습니다(예: src/types/memory.ts:82–84). 따라서 src/components/memory/RecordItem/PollRecord.tsx의 key={option.id}는 undefined 경고를 유발하지 않으며 voteItemId로 변경할 필요가 없습니다.

Likely an incorrect or invalid review comment.

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

11-12: 진행 상태 체크 관련 import 추가 적절

페이지 단에서 방 상태 확인을 위한 의존성 추가가 목적에 부합합니다.


319-323: FAB 조건 렌더링 방향성 OK

완료 방에서 작성 버튼을 숨기는 정책은 요구사항과 일치합니다. tri‑state 반영 시 조건을 roomCompleted === false로 유지하세요.

검증 결과: 제공하신 스크립트 출력이 "No files were searched"로 리포지토리 검색이 수행되지 않아 확인이 불충분합니다. 아래로 재실행해 주세요:

#!/bin/bash
set -euo pipefail

echo "isRoomCompleted 사용 위치:"
rg -n --hidden -uu -S 'isRoomCompleted\s*\(' -g '!node_modules/**' -C2 || true

echo
echo "MessageInput 사용 파일:"
rg -n --hidden -uu -S '<MessageInput' -g '!node_modules/**' -C2 || true

echo
echo "roomCompleted 가드가 없는 MessageInput 파일(후보):"
python - <<'PY'
import subprocess
p = subprocess.run(['rg','-n','--hidden','-uu','-S','<MessageInput','-g','!node_modules/**','-l'], capture_output=True, text=True)
files = [f for f in p.stdout.splitlines() if f]
unguarded=[]
for f in files:
    try:
        with open(f,encoding='utf-8',errors='ignore') as fh:
            t=fh.read()
            if 'roomCompleted' not in t:
                unguarded.append(f)
    except: pass
print('\n'.join(unguarded))
PY
src/components/common/CommentBottomSheet/GlobalCommentBottomSheet.tsx (3)

2-12: 라우팅 파라미터/스낵바/방 상태 체크 import 추가 적절

목표한 UX(완료 방 입력 비노출, 서버 메시지 스낵바 전달)에 필요한 의존성이 잘 추가되었습니다.


24-24: roomId 비존재 시 정책 확인 필요

일부 라우트에서 roomId가 없으면 상태 체크가 스킵되어 입력이 그대로 노출됩니다. 의도한 동작인지 확인 바랍니다(예: 전역 댓글 시트가 그룹 외 페이지에서 열릴 수 있는지).


79-85: 서버/네트워크 에러 스낵바 전달 좋습니다

실패 사유를 사용자에게 명확히 전달합니다. 서버 메시지의 길이/민감도에 따른 truncate/정제 로직은 추후 필요 시 고려하세요.

Also applies to: 88-92

@heeeeyong heeeeyong added this to the 9월 3주차 QA milestone Sep 23, 2025
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 (3)
src/api/comments/postLike.ts (1)

1-31: 반환 타입을 지켜주세요.

error.response.dataany로 추론되면서 postLike 전체가 Promise<any>로 바뀌어 호출부에서 isSuccess·data 구조를 컴파일 단계에서 검증할 수 없게 됩니다. 새로 추가한 필드를 안전하게 활용하려면 반환 타입을 명시하고 Axios 에러인 경우에만 동일한 응답 스펙을 돌려주도록 가드해 주세요.

+import { isAxiosError } from 'axios';
 import { apiClient } from '../index';
@@
-export const postLike = async (commentId: number, type: boolean) => {
+export const postLike = async (commentId: number, type: boolean): Promise<PostLikeResponse> => {
@@
-  } catch (error: any) {
+  } catch (error) {
     console.error('댓글 좋아요 API 오류:', error);
     // 서버에서 에러 응답을 보낸 경우 해당 응답을 반환
-    if (error.response?.data) {
-      return error.response.data;
+    if (isAxiosError<PostLikeResponse>(error) && error.response?.data) {
+      return error.response.data;
     }
     throw error;
   }
src/api/record/postVote.ts (1)

1-19: 타입 안정성을 유지해주세요.

postVote 역시 error.response.data 때문에 Promise<any>로 추론되고 있어, 호출부에서 isSuccess 등의 필드를 오타 없이 다루는 안전장치가 사라졌습니다. 반환 타입을 명시하고 Axios 에러인지 확인한 뒤 동일 스키마일 때만 값을 반환하도록 정리해 주세요.

+import { isAxiosError } from 'axios';
 import { apiClient } from '../index';
 import type { VoteRequest, VoteData, ApiResponse } from '@/types/record';
@@
-export const postVote = async (roomId: number, voteId: number, voteData: VoteRequest) => {
+export const postVote = async (
+  roomId: number,
+  voteId: number,
+  voteData: VoteRequest,
+): Promise<VoteResponse> => {
   try {
     const response = await apiClient.post<VoteResponse>(`/rooms/${roomId}/vote/${voteId}`, voteData);
     return response.data;
-  } catch (error: any) {
+  } catch (error) {
     console.error('투표 API 오류:', error);
     // 서버에서 에러 응답을 보낸 경우 해당 응답을 반환
-    if (error.response?.data) {
-      return error.response.data;
+    if (isAxiosError<VoteResponse>(error) && error.response?.data) {
+      return error.response.data;
     }
     throw error;
   }
src/api/comments/postReply.ts (1)

1-30: 댓글 작성 API도 동일하게 타입을 보존해야 합니다.

postReplyPromise<any>로 변하면서 댓글 작성 결과 객체의 구조를 컴파일 타임에 검증할 수 없습니다. Axios 에러만 안전하게 캐치하도록 수정해 타입 안정성을 회복해 주세요.

+import { isAxiosError } from 'axios';
 import { apiClient } from '../index';
@@
-export const postReply = async (postId: number, request: PostReplyRequest) => {
+export const postReply = async (
+  postId: number,
+  request: PostReplyRequest,
+): Promise<PostReplyResponse> => {
   try {
     const response = await apiClient.post<PostReplyResponse>(`/comments/${postId}`, request);
     return response.data;
-  } catch (error: any) {
+  } catch (error) {
     console.error('댓글 작성 API 오류:', error);
     // 서버에서 에러 응답을 보낸 경우 해당 응답을 반환
-    if (error.response?.data) {
-      return error.response.data;
+    if (isAxiosError<PostReplyResponse>(error) && error.response?.data) {
+      return error.response.data;
     }
     throw error;
   }
🧹 Nitpick comments (4)
src/components/memory/RecordItem/PollRecord.tsx (1)

93-106: isHighest 계산 시 불필요한 O(n²) 반복을 제거해주세요.

현재 currentOptions.map 루프 안에서 Math.max(...response.data.voteItems.map(...))가 매 옵션마다 다시 계산되고 있어, 옵션 수가 많을 경우 불필요한 계산 부담이 큽니다. 응답 받은 voteItems를 한 번만 순회해 최대 득표수를 구한 뒤 재사용하도록 리팩터링하는 편이 좋겠습니다. 예시는 아래와 같습니다.

-        const updatedOptions = currentOptions.map(opt => {
-          const updatedItem = response.data.voteItems.find(
-            (item: PollOption) => item.voteItemId === opt.voteItemId,
-          );
+        const voteItems = response.data.voteItems;
+        const maxCount = Math.max(...voteItems.map((item: PollOption) => item.count));
+        const updatedOptions = currentOptions.map(opt => {
+          const updatedItem = voteItems.find(
+            (item: PollOption) => item.voteItemId === opt.voteItemId,
+          );
           if (updatedItem) {
             return {
               ...opt,
               percentage: updatedItem.percentage,
               count: updatedItem.count,
               isVoted: updatedItem.isVoted,
-              isHighest:
-                updatedItem.count ===
-                Math.max(...response.data.voteItems.map((item: PollOption) => item.count)),
+              isHighest: updatedItem.count === maxCount,
             };
src/api/roomPosts/postRoomPostLike.ts (1)

15-21: AxiosError를 활용해 오류 타입을 명확히 해주세요.
Line [15]에서 errorany로 선언하면 response 존재 여부를 정적으로 보장받지 못해 유지보수 시 추론이 어려워집니다. Axios 환경이라면 axios.isAxiosError로 분기해 RoomPostLikeResponse 스펙을 확실히 지킬 수 있도록 타입을 좁혀 주세요.

+import axios from 'axios';
...
-  } catch (error: any) {
-    console.error('방 게시물 좋아요 API 오류:', error);
-    if (error.response?.data) {
-      return error.response.data;
-    }
-    throw error;
-  }
+  } catch (error) {
+    console.error('방 게시물 좋아요 API 오류:', error);
+    if (axios.isAxiosError<RoomPostLikeResponse>(error)) {
+      const errorData = error.response?.data;
+      if (errorData) {
+        return errorData;
+      }
+    }
+    throw error;
+  }
src/components/common/Post/SubReply.tsx (1)

50-62: 좋아요 카운트 감소 시 음수로 내려가지 않도록 보정해 주세요.
Line [54]에서 실패한 동기화나 초기 데이터 불일치로 prev가 0인데 response.data.isLikedfalse로 내려오면 UI에 -1이 노출됩니다. 서버 응답의 카운트 값을 그대로 쓰거나, 최소 0으로 클램프해서 사용자 경험을 보호하는 편이 안전합니다.

-        setCurrentLikeCount(prev => (response.data.isLiked ? prev + 1 : prev - 1));
+        setCurrentLikeCount(prev => {
+          const next = response.data.isLiked ? prev + 1 : prev - 1;
+          return Math.max(next, 0);
+        });
src/components/common/Post/Reply.tsx (1)

44-55: 댓글 좋아요 카운트도 음수 방지를 위해 클램프가 필요합니다.
Line [47] 역시 prev - 1이 즉시 실행되는데, 동시성 이슈나 초기 값 불일치가 있으면 -1이 내려옵니다. 위 SubReply와 동일하게 최소값을 0으로 보정하거나 서버가 내려주는 최신 카운트를 직접 반영하는 방식으로 보완해 주세요.

-        setLikeCount(prev => (response.data.isLiked ? prev + 1 : prev - 1));
+        setLikeCount(prev => {
+          const next = response.data.isLiked ? prev + 1 : prev - 1;
+          return Math.max(next, 0);
+        });
📜 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 0c2593b and 962a674.

📒 Files selected for processing (9)
  • src/api/comments/postLike.ts (2 hunks)
  • src/api/comments/postReply.ts (1 hunks)
  • src/api/record/postVote.ts (1 hunks)
  • src/api/roomPosts/postRoomPostLike.ts (1 hunks)
  • src/components/common/Post/Reply.tsx (1 hunks)
  • src/components/common/Post/SubReply.tsx (1 hunks)
  • src/components/common/TitleHeader.tsx (1 hunks)
  • src/components/memory/RecordItem/PollRecord.tsx (7 hunks)
  • src/components/memory/RecordItem/RecordItem.tsx (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/api/comments/postLike.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
src/api/comments/postReply.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
src/components/memory/RecordItem/PollRecord.tsx (2)
src/types/memory.ts (1)
  • PollOption (82-90)
src/components/memory/RecordItem/PollRecord.styled.ts (3)
  • PollOption (23-32)
  • PollNumber (44-51)
  • PollText (53-60)
src/api/record/postVote.ts (1)
src/api/index.ts (1)
  • apiClient (7-13)
🔇 Additional comments (5)
src/components/common/TitleHeader.tsx (1)

81-83: TitleHeader 우측 버튼 클릭 방어 로직 추가 또는 사용처 검증 필요
isNextActive가 기본값(false)일 때 onRightClick이 undefined로 설정되어 기존에 암묵적으로 클릭 가능하던 화면의 우측 버튼이 동작을 멈춥니다. 모든 TitleHeader 사용처에서 isNextActive를 명시했는지 검토하거나, 기본값일 때도 클릭 이벤트가 동작하도록 방어 로직을 추가하세요.

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

84-89: 서버 오류 메시지 우선 노출 👍
직접 작성한 문구보다 백엔드에서 내려오는 response.message를 우선적으로 보여주도록 바꾼 덕분에 QA 피드백과도 잘 맞습니다.


236-243: 실패 시에도 팝업 정리한 점 좋습니다
에러 처리 전에 closePopup()을 호출해서 레이어가 잔류하지 않도록 정리해 둔 덕분에 UI 일관성이 확보됩니다.


286-303: MoreMenu 액션 후 Confirm 즉시 닫힘 여부 확인 필요
openMoreMenuonClose: closePopup을 넘기면서, MoreMenu 컴포넌트가 콜백 실행 뒤에 onClose?.()를 호출하는 구조라면 handlePinConfirm에서 띄운 Confirm이 바로 닫혀 버릴 수 있습니다. 실제 QA 시나리오에서 “텍스트 기록 → … → 핀하기”를 눌렀을 때 확인 모달이 정상적으로 유지되는지 꼭 한 번 확인 부탁드립니다. 만약 문제가 재현되면 handlePinConfirm에서 먼저 closePopup()으로 메뉴를 닫고 이후 openConfirm을 호출하는 구조로 조정하면 안전할 것 같습니다.


311-320: 의존성 배열 보강 감사합니다
shouldBlurclosePopup을 포함시켜 최신 레퍼런스를 유지하도록 정리된 점이 좋습니다.

@ljh130334 ljh130334 merged commit 040ef0f into develop Sep 26, 2025
2 checks 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: 2

Caution

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

⚠️ Outside diff range comments (1)
src/components/group/HotTopicSection.tsx (1)

137-139: 터치 이벤트에서 preventDefault() 사용 주의

handleTouchStart에서 e.preventDefault()를 호출하면 터치 스크롤이 차단될 수 있습니다. 이는 모바일 사용자 경험을 해칠 수 있습니다.

슬라이드 드래그와 페이지 스크롤을 구분하기 위해 수평 이동을 감지한 후에만 스크롤을 차단하는 방식을 고려해보세요:

  const handleTouchStart = (e: React.TouchEvent) => {
-    e.preventDefault();
     handleDragStart(e.touches[0].clientX);
   };

   const handleTouchMove = (e: React.TouchEvent) => {
-    e.preventDefault();
+    if (dragStateRef.current.hasMoved) {
+      e.preventDefault();
+    }
     handleDragMove(e.touches[0].clientX);
   };
🧹 Nitpick comments (4)
src/components/group/HotTopicSection.tsx (2)

55-60: 터치 이벤트 핸들링 개선 필요

현재 코드에서 몇 가지 개선이 필요합니다:

  1. handleVoteClick에서 React.TouchEvent를 처리하지만 실제로는 onClick에만 바인딩되어 있어 터치 이벤트가 전달되지 않습니다.
  2. handleVoteTouchEnd에서 불필요한 e.preventDefault()가 있습니다. 이미 handleVoteTouchStart에서 이벤트 전파를 막고 있으므로 중복됩니다.
  3. 터치와 마우스 이벤트 로직이 중복되어 있습니다.
-  const handleVoteClick = (e: React.MouseEvent | React.TouchEvent, poll: Poll) => {
+  const handleVoteClick = (e: React.MouseEvent, poll: Poll) => {
     e.stopPropagation();
     if (!isDragging || !dragStateRef.current.hasMoved) {
       onPollClick(poll.pageNumber);
     }
   };

   // 터치 이벤트 핸들러
   const handleVoteTouchEnd = (e: React.TouchEvent, poll: Poll) => {
-    e.preventDefault();
     e.stopPropagation();
     if (!isDragging || !dragStateRef.current.hasMoved) {
       onPollClick(poll.pageNumber);
     }
   };

Also applies to: 63-69, 71-73


254-256: HotTopicSectionHeader에서 cursor 스타일 제거
클릭 핸들러가 없으므로 src/components/group/HotTopicSection.styled.ts에서 cursor: pointer;를 삭제하세요.

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

165-183: 비동기 상태 업데이트 취소 처리 및 안정성 보강 제안
아래처럼 cancelled 플래그를 추가해 언마운트 혹은 roomId 변경 시 stale 응답으로 인한 setState 호출을 방지하세요.

  useEffect(() => {
+   let cancelled = false;
    const checkRoomStatus = async () => {
      if (!roomId) return;
      try {
-       const response = await getRoomPlaying(parseInt(roomId));
+       const response = await getRoomPlaying(Number(roomId));
+       if (!cancelled && response.isSuccess) {
          const completed = isRoomCompleted(response.data.progressEndDate);
          setRoomCompleted(completed);
-     }
+       }
      } catch (error) {
-       console.error('모임방 상태 확인 오류:', error);
+       if (!cancelled) {
+         console.error('모임방 상태 확인 오류:', error);
+       }
      }
    };
    checkRoomStatus();
+   return () => { cancelled = true; };
  }, [roomId]);

35-47: maxCount 계산을 map 외부로 옮기기
src/pages/memory/Memory.tsx에서 pollOptions 생성 시 매 항목마다 Math.max(...post.voteItems.map(...))를 호출해 O(n²)이 됩니다. post.voteItems.map(v ⇒ v.count||0)로 counts 배열을 만들고 Math.max를 한 번만 실행하도록 수정하세요.

📜 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 962a674 and abd1816.

📒 Files selected for processing (2)
  • src/components/group/HotTopicSection.tsx (6 hunks)
  • src/pages/memory/Memory.tsx (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/memory/Memory.tsx (3)
src/api/rooms/getRoomPlaying.ts (1)
  • getRoomPlaying (65-79)
src/utils/roomStatus.ts (1)
  • isRoomCompleted (10-24)
src/pages/memory/Memory.styled.ts (1)
  • FloatingElements (48-58)
src/components/group/HotTopicSection.tsx (1)
src/components/group/HotTopicSection.styled.ts (2)
  • HotTopicSection (4-13)
  • HotTopicSectionHeader (15-20)
🔇 Additional comments (3)
src/pages/memory/Memory.tsx (3)

11-12: LGTM: 완료 상태 확인 의존성 추가 적절

getRoomPlaying, isRoomCompleted 모두 아래 useEffect에서 정상 사용됩니다.


90-92: LGTM: 완료 상태 state 추가 적절

후속 렌더 조건부 처리와 잘 연결됩니다.


330-334: LGTM: 완료된 방에서 FAB 숨김 처리 충족

PR 의도(완료된 방에서 작성 UI 숨김)에 부합합니다.

테스트 데이터로 다음을 확인 부탁드립니다:

  • 완료된 방 진입 시 FAB가 표시되지 않아야 함.
  • 진행 중인 방 진입 시 FAB가 정상 표시되어야 함.
  • 경계일(마감일 당일)에서 의도한 표시/숨김 동작이 맞는지 확인.

polls: Poll[];
hasPolls: boolean;
onClick: () => void;
onClick?: () => void;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

onClick prop이 사용되지 않음

props에서 onClick이 optional로 정의되어 있지만 컴포넌트 내부에서 실제로 사용되지 않습니다. 사용하지 않는 prop은 제거하는 것이 좋습니다.

interface HotTopicSectionProps {
  polls: Poll[];
  hasPolls: boolean;
-  onClick?: () => void;
  onPollClick: (pageNumber: number) => void;
}

Also applies to: 39-39

🤖 Prompt for AI Agents
In src/components/group/HotTopicSection.tsx around lines 35 and 39, the props
declare an optional onClick property but the component never uses it; remove
onClick from the prop type/interface (and any related prop forwarding) or, if
intended, wire it up to the correct clickable element (e.g., pass it to the root
button/div or list item) and ensure proper typing—update the component props
definition and usages accordingly to either eliminate the unused prop or attach
it to the interactive element.

Comment on lines +65 to +82
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
const pageParam = searchParams.get('page');
const filterParam = searchParams.get('filter');

if (pageParam && filterParam === 'poll') {
const page = parseInt(pageParam);
if (!isNaN(page)) {
console.log('✅ 페이지 필터 적용:', { page });
setSelectedPageRange({ start: page, end: page });
setActiveFilter('page');
setActiveTab('group');

navigate(location.pathname, { replace: true });
}
}
}, [location.search]);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

URL 쿼리 파싱: 'filter=poll' 네이밍 불일치 가능, parseInt/로그 정리 제안

  • 내부 상태는 FilterType = 'page' | 'overall'인데, 쿼리는 filter=poll을 기대합니다. 의도(“투표 페이지 필터”)라면 OK지만, 일관성 측면에서 filter=page로 맞추거나 쿼리 파라미터명을 명확히 하는 것을 권장합니다.
  • parseInt 대신 Number가 간결합니다.
  • 콘솔 로그는 배포 시 노이즈가 될 수 있어 제거 권장.
-    if (pageParam && filterParam === 'poll') {
-      const page = parseInt(pageParam);
+    if (pageParam && filterParam === 'poll') {
+      const page = Number(pageParam);
       if (!isNaN(page)) {
-        console.log('✅ 페이지 필터 적용:', { page });
         setSelectedPageRange({ start: page, end: page });
         setActiveFilter('page');
         setActiveTab('group');
         navigate(location.pathname, { replace: true });
       }
     }

다른 라우팅/딥링크에서 filter=poll을 참조하는 곳이 있는지 확인 부탁드립니다. 있으면 유지, 없으면 filter=page로 통일 고려.


🏁 Script executed:

#!/bin/bash
# filter=poll 사용처 확인
rg -nP -C3 'filter=poll'

Length of output: 557


URL 쿼리 파라미터 filter=pollfilter=page 통일, parseIntNumber, console.log 제거

  • src/pages/memory/Memory.tsx: filterParam==='poll'filterParam==='page', const page = Number(pageParam), console.log 삭제
  • src/pages/groupDetail/ParticipatedGroupDetail.tsx: navigate URL의 &filter=poll&filter=page
--- src/pages/memory/Memory.tsx
@@ -65,12 +65,11 @@
-    if (pageParam && filterParam === 'poll') {
-      const page = parseInt(pageParam);
+    if (pageParam && filterParam === 'page') {
+      const page = Number(pageParam);
       if (!isNaN(page)) {
-        console.log('✅ 페이지 필터 적용:', { page });
         setSelectedPageRange({ start: page, end: page });
         setActiveFilter('page');
         setActiveTab('group');
--- src/pages/groupDetail/ParticipatedGroupDetail.tsx
@@ -187,7 +187,7 @@
-    navigate(`/rooms/${roomId}/memory?page=${pageNumber}&filter=poll`);
+    navigate(`/rooms/${roomId}/memory?page=${pageNumber}&filter=page`);
📝 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
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
const pageParam = searchParams.get('page');
const filterParam = searchParams.get('filter');
if (pageParam && filterParam === 'poll') {
const page = parseInt(pageParam);
if (!isNaN(page)) {
console.log('✅ 페이지 필터 적용:', { page });
setSelectedPageRange({ start: page, end: page });
setActiveFilter('page');
setActiveTab('group');
navigate(location.pathname, { replace: true });
}
}
}, [location.search]);
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
const pageParam = searchParams.get('page');
const filterParam = searchParams.get('filter');
if (pageParam && filterParam === 'page') {
const page = Number(pageParam);
if (!isNaN(page)) {
setSelectedPageRange({ start: page, end: page });
setActiveFilter('page');
setActiveTab('group');
navigate(location.pathname, { replace: true });
}
}
}, [location.search]);
Suggested change
useEffect(() => {
const searchParams = new URLSearchParams(location.search);
const pageParam = searchParams.get('page');
const filterParam = searchParams.get('filter');
if (pageParam && filterParam === 'poll') {
const page = parseInt(pageParam);
if (!isNaN(page)) {
console.log('✅ 페이지 필터 적용:', { page });
setSelectedPageRange({ start: page, end: page });
setActiveFilter('page');
setActiveTab('group');
navigate(location.pathname, { replace: true });
}
}
}, [location.search]);
navigate(`/rooms/${roomId}/memory?page=${pageNumber}&filter=page`);
🤖 Prompt for AI Agents
In src/pages/memory/Memory.tsx around lines 65 to 82, update the URL query
handling so it checks for filterParam === 'page' (not 'poll'), convert the
pageParam using Number(pageParam) instead of parseInt, and remove the
console.log call; after converting, validate with isNaN and then call
setSelectedPageRange, setActiveFilter('page'), setActiveTab('group') and
navigate(location.pathname, { replace: true }) as before. Also update the
related navigate call in src/pages/groupDetail/ParticipatedGroupDetail.tsx to
use &filter=page instead of &filter=poll.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 BugFix Something isn't working ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants