Skip to content

feat: 고객 리뷰 관리 (작성 가능/내 리뷰) - #22

Merged
juengseulki merged 8 commits into
devfrom
feature/customer-reviews
Jul 28, 2026
Merged

feat: 고객 리뷰 관리 (작성 가능/내 리뷰)#22
juengseulki merged 8 commits into
devfrom
feature/customer-reviews

Conversation

@juengseulki

@juengseulki juengseulki commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

📋 작업 내용

  • 고객 리뷰 관리 기능 추가 (작성 가능한 리뷰 / 내가 작성한 리뷰)
  • 헤더 프로필 메뉴에서 리뷰 페이지 진입 연결
  • 내가 작성한 리뷰 카드 클릭 시 기사님 상세 페이지로 이동

🔥 변경 사항

  • 리뷰 타입·API·mock·hooks 추가 (/reviews/reviewable, /reviews/me, POST /reviews)
  • /reviews/writable, /reviews/me 페이지 및 리뷰 UI 컴포넌트 추가 (목록, 작성 모달, 별점, 탭, 빈 상태)
  • Header 프로필 드롭다운에 리뷰 메뉴 연결 및 세션 구독 반영
  • 내가 작성한 리뷰 카드 → /movers/{moverId} 상세 이동
  • 원격 알림 Header 변경과 리뷰 메뉴 병합

✅ 체크리스트

  • 로컬에서 정상 동작을 확인했습니다.
  • 기존 기능에 영향을 주지 않는지 확인했습니다.
  • 불필요한 console.log를 제거했습니다.
  • lint를 통과했습니다.
  • README 또는 문서를 수정했습니다. (필요 시)
  • API 명세와 일치하는지 확인했습니다.

📷 스크린샷 (선택)

localhost_3000_reviews_writable localhost_3000_reviews_writable(iPad Air) localhost_3000_reviews_writable(iPhone 12 Pro) localhost_3000_reviews_writable(iPhone 12 Pro)모달 localhost_3000_reviews_writable(iPad Air)모달 localhost_3000_reviews_writableahekf localhost_3000_reviews localhost_3000_reviews(iPad Air) localhost_3000_reviews(iPhone 12 Pro)

🔗 관련 이슈

Closes #


💬 To Reviewer

  • 현재 리뷰 API는 mock 우선이며, 실제 연동 시 src/lib/api/reviews.ts의 주석을 해제하면 됩니다.
  • 기사님 상세 페이지(/movers/[id])가 아직 없으면 리뷰 카드 클릭 시 404가 날 수 있습니다.
  • Header는 알림 패널(원격)과 리뷰 프로필 드롭다운(로컬)을 함께 병합한 상태입니다.

Summary by CodeRabbit

  • 새 기능
    • “작성 가능한 리뷰/내가 작성한 리뷰” 탭과 페이지(목록, 빈 상태, 오류 시 재시도) 제공
    • 리뷰 카드, 별점 컴포넌트, 작성 모달(별점/내용 검증) 도입
    • 작성 가능 목록 페이지네이션 제공
  • 개선
    • /reviews 접속 시 작성 가능 리뷰로 자동 이동
    • 로그인 상태 즉시 반영, 알림/프로필 드롭다운의 키보드 접근성 및 닫기(ESC/외부 클릭) 개선
  • 버그 수정
    • 날짜 표시 예외에 대한 안전 처리, 제출 중/비활성 시 모달 닫기 동작 강화
  • 스타일
    • 탭 하단 그림자 효과 추가

jeungseulki and others added 5 commits July 27, 2026 19:17
작성 가능/내 리뷰 조회와 리뷰 작성 흐름을 mock 우선으로 연결할 수 있게 데이터 레이어를 구성합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
작성 가능 리뷰·내가 작성한 리뷰 목록과 작성 모달을 견적 페이지 패턴에 맞춰 구성합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
프로필 드롭다운에서 작성 가능/내 리뷰로 이동할 수 있게 하고, 인증 세션 구독과 앱 라우트를 함께 연결합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
리뷰 카드 클릭 시 해당 기사님 상세 페이지로 연결되도록 라우트를 추가합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
axios 대신 공통 fetch 클라이언트를 쓰도록 맞추고, 페이지네이션 응답용 getPaginated를 추가합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f9e59bb4-9fbb-4ff4-904a-ca114f1b2184

📥 Commits

Reviewing files that changed from the base of the PR and between e1f3834 and 1a42f6b.

📒 Files selected for processing (1)
  • src/components/review/ReviewWriteModal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/review/ReviewWriteModal.tsx

📝 Walkthrough

Walkthrough

리뷰 관리 경로, 탭과 공통 셸, 작성 가능 리뷰·내 리뷰 목록, 리뷰 작성 모달과 mock API가 추가되었다. 헤더는 인증 세션 구독과 접근성 프로필 메뉴를 지원하며, 페이지네이션과 리뷰 생성 후 쿼리 갱신 흐름이 연결되었다.

Changes

리뷰 관리 기능

Layer / File(s) Summary
리뷰 계약과 API 기반
src/types/review.ts, src/lib/constants/appRoutes.ts, src/lib/api/fetchInstance.ts, src/lib/utils/estimateFormat.ts
리뷰 타입, 관련 라우트, 페이지네이션 응답 요청 및 안전한 날짜 포맷이 추가되었다.
리뷰 데이터 흐름
src/lib/mocks/reviews.mock.ts, src/lib/api/reviews.ts, src/hooks/*Review*.ts
작성 가능 리뷰와 내 리뷰 조회, mock 페이지네이션, 리뷰 생성 및 관련 쿼리 무효화가 구현되었다.
리뷰 페이지 셸과 공통 UI
src/app/reviews/*, src/components/review/ReviewsShell.tsx, src/components/review/ReviewTabs.tsx, src/components/review/ReviewPageFrame.tsx, src/components/review/ReviewEmptyState.tsx, src/components/review/ReviewStarRating.tsx, src/styles/tokens.theme.css
리뷰 레이아웃·탭·공통 프레임·빈 상태·별점 컴포넌트와 페이지 진입점이 추가되었다.
작성 가능 리뷰 흐름
src/components/review/WritableReviewCard.tsx, src/components/review/WritableReviewsPageClient.tsx, src/components/review/ReviewWriteModal.tsx, src/components/common/Modal/ModalClose.tsx
작성 가능한 견적을 카드로 표시하고, 입력 검증을 거쳐 리뷰 생성 모달과 결과 토스트를 연결했다.
내 리뷰 목록 흐름
src/components/review/MyReviewCard.tsx, src/components/review/MyReviewsPageClient.tsx
내 리뷰를 카드 목록으로 표시하고 로딩·오류·빈 상태·페이지네이션을 처리한다.

인증 세션 기반 헤더

Layer / File(s) Summary
인증 세션 변경 동기화
src/lib/auth/session.ts, src/lib/dev-auth.ts
세션 변경 이벤트 구독과 개발 토큰 변경 후 알림 호출이 추가되었다.
헤더 프로필 메뉴
src/components/common/Header/Header.tsx
세션 기반 로그인 상태, 프로필 드롭다운, 알림 버튼, 외부 클릭 및 키보드 메뉴 조작이 구현되었다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Customer
  participant WritableReviewsPageClient
  participant ReviewWriteModal
  participant useCreateReview
  participant createReview

  Customer->>WritableReviewsPageClient: 리뷰 작성 선택
  WritableReviewsPageClient->>ReviewWriteModal: 선택 견적 전달
  Customer->>ReviewWriteModal: 별점·내용 제출
  ReviewWriteModal->>useCreateReview: 리뷰 생성 실행
  useCreateReview->>createReview: 리뷰 데이터 전달
  createReview-->>useCreateReview: 생성 결과 반환
  useCreateReview-->>ReviewWriteModal: 성공 또는 오류 전달
  ReviewWriteModal-->>WritableReviewsPageClient: 닫기 또는 토스트 표시
Loading

Possibly related PRs

Suggested labels: 🏢코드리뷰

Suggested reviewers: obebe-creator, 9g-g9

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 작성 가능 리뷰와 내 리뷰를 포함한 고객 리뷰 관리 기능 추가를 잘 요약한 제목입니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/customer-reviews

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (7)
src/components/review/ReviewWriteModal.tsx (1)

53-80: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

검증 분기가 도달 불가능한 죽은 코드입니다.

isSubmitDisabledrating < 1 || trimmedContent.length < MIN_CONTENT_LENGTH 를 이미 포함하므로, 그 조건에서는 버튼이 눌리지 않아 handleSubmit 이 호출되지 않습니다. 결과적으로 ratingError / contentError 는 절대 화면에 나타나지 않고, 사용자는 버튼이 왜 비활성인지 알 수 없습니다.

둘 중 하나로 정리하는 편이 좋습니다.

  • 버튼은 isPending 일 때만 비활성화하고 검증은 handleSubmit 에서 수행 (에러 메시지가 실제로 노출됨, 권장)
  • 또는 검증 분기를 제거하고 비활성 사유를 정적 안내 문구로 대체
♻️ 제안 (에러 메시지를 살리는 방향)
-  const isSubmitDisabled =
-    createMutation.isPending || rating < 1 || trimmedContent.length < MIN_CONTENT_LENGTH;
+  const isSubmitDisabled = createMutation.isPending;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/review/ReviewWriteModal.tsx` around lines 53 - 80, Update
isSubmitDisabled so it only reflects createMutation.isPending, allowing
handleSubmit to run for invalid rating or content and display
ratingError/contentError. Keep the existing validation and mutation behavior in
handleSubmit unchanged.
src/components/review/WritableReviewsPageClient.tsx (2)

41-44: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

page state 는 클램핑되지 않아 목록이 줄어들면 값이 남습니다.

currentPage 는 파생값으로 보정되지만 page 자체는 그대로입니다. 리뷰 작성 후 목록이 줄어 2페이지가 사라진 상태에서 다시 항목이 늘어나면, 사용자가 1페이지를 보고 있었는데 2페이지로 점프합니다. 목록 갱신 흐름이 잦은 화면이라 정리해 두면 좋습니다.

♻️ 제안
   const handlePageChange = (nextPage: number) => {
-    setPage(nextPage);
+    setPage(Math.min(Math.max(1, nextPage), totalPages));
     window.scrollTo({ top: 0, behavior: "smooth" });
   };

또는 currentPage !== page 일 때 setPage(currentPage) 로 동기화하는 방법도 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/review/WritableReviewsPageClient.tsx` around lines 41 - 44,
Synchronize the writable reviews page state with the clamped currentPage value
so page does not retain an invalid page after the review list shrinks. Update
the pagination logic around handlePageChange and currentPage to
setPage(currentPage) whenever they differ, while preserving normal navigation
behavior and avoiding unnecessary updates.

26-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

totalPages 가 두 곳에서 따로 계산됩니다 — 단일 소스로 정리해 주세요.

Line 27에서 totalPages 를 직접 계산해 currentPage 클램핑에 쓰고, Line 30-33에서 buildMockPagination 이 같은 값을 다시 계산해 Line 79/83에서 사용합니다. 두 계산이 어긋나면 클램핑 범위와 PaginationpageCount 가 불일치합니다. 또한 buildMockPagination 은 이름 그대로 mock 유틸인데 여기서는 totalPages 하나만 쓰고 있어, 실 API 전환 시 잔재로 남기 쉽습니다.

♻️ 제안
   const totalCount = data?.length ?? 0;
-  const totalPages = Math.max(1, Math.ceil(totalCount / REVIEWABLE_PAGE_LIMIT) || 1);
+  const totalPages = Math.max(1, Math.ceil(totalCount / REVIEWABLE_PAGE_LIMIT));
   const currentPage = totalCount === 0 ? 1 : Math.min(Math.max(1, page), totalPages);
 
-  const pagination = useMemo(
-    () => buildMockPagination(totalCount, currentPage, REVIEWABLE_PAGE_LIMIT),
-    [totalCount, currentPage],
-  );
-

그리고 Line 79/83의 pagination.totalPagestotalPages 로 교체하고, 미사용이 된 buildMockPagination import를 제거하면 됩니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/review/WritableReviewsPageClient.tsx` around lines 26 - 39,
Use the locally computed totalPages as the single pagination source: replace
pagination.totalPages references in the page controls with totalPages, remove
the buildMockPagination use and its import, and retain currentPage clamping and
pageItems behavior based on the shared totalPages value.
src/components/common/Header/Header.tsx (1)

174-208: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

min-w-[200px], top-[calc(100%+8px)] 임의값 대신 spacing 토큰 사용을 검토해 주세요.

src/styles/tokens.theme.css 의 spacing 토큰으로 대체 가능하면 다른 드롭다운과 값이 어긋나는 것을 막을 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/Header/Header.tsx` around lines 174 - 208, Update the
profile menu container in the isProfileMenuOpen rendering to replace the
arbitrary min-w-[200px] and top-[calc(100%+8px)] values with the corresponding
spacing tokens from tokens.theme.css, matching the established dropdown spacing
conventions.

Source: Path instructions

src/lib/dev-auth.ts (1)

47-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

세션 변경 알림 블록이 두 함수에 복제되어 있고 rejection 처리가 없습니다. 동일한 동적 import + .then() 패턴이 두 곳에 그대로 반복되어, import 실패 시 양쪽 모두 unhandled rejection 이 됩니다. 파일 내 헬퍼 하나로 통합하고 .catch() 를 붙이세요.

  • src/lib/dev-auth.ts#L47-L50: notifySessionChangeAsync() 헬퍼를 정의하고 이 블록을 호출로 대체.
  • src/lib/dev-auth.ts#L60-L62: 같은 헬퍼 호출로 대체.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/dev-auth.ts` around lines 47 - 50, In src/lib/dev-auth.ts lines
47-50, define a shared notifySessionChangeAsync() helper that performs the
dynamic session import, calls notifyAuthSessionChange, and handles failures with
catch; replace the duplicated block with this helper call. Apply the same helper
replacement at lines 60-62, with no separate direct change beyond using the
shared helper.
src/components/review/ReviewStarRating.tsx (1)

62-81: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

radiogroup인데 방향키 탐색(roving tabindex)이 없습니다.

각 별이 role="radio"이지만 기본 tabIndex를 그대로 사용해 Tab으로 5개를 모두 개별 이동합니다. WAI-ARIA radiogroup 패턴은 화살표 키로 옵션을 이동하고 그룹 내 하나만 tab-stop이어야 하는데, 현재는 이 규약과 어긋나 스크린리더 사용자의 기대 동작과 다릅니다.

♿ roving tabindex 적용 제안 (개념)
         <button
           key={starValue}
           type="button"
           role="radio"
           aria-checked={starValue === clamped}
           aria-label={`${label} ${starValue}점`}
           disabled={disabled}
+          tabIndex={starValue === (clamped || 1) ? 0 : -1}
+          onKeyDown={(e) => {
+            if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
+              e.preventDefault();
+              const next = e.key === "ArrowRight"
+                ? Math.min(5, starValue + 1)
+                : Math.max(1, starValue - 1);
+              onChange(next);
+            }
+          }}
           className="focus-visible:ring-border-brand rounded-4 focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed"
           onClick={() => onChange(starValue)}
         >

as per path instructions, "키보드 접근성, focus·disabled·hover·active 상태, aria 속성, 모달 focus 관리, 색상 대비, 모바일 터치 영역을 확인한다."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/review/ReviewStarRating.tsx` around lines 62 - 81, Review the
star buttons rendered in ReviewStarRating and implement the WAI-ARIA radiogroup
pattern with roving tabindex: keep exactly one enabled star at tabIndex 0 and
assign -1 to the others, then support ArrowLeft/ArrowRight navigation by moving
focus and updating the selected value. Preserve disabled behavior, aria-checked
state, and existing click handling while ensuring the focused option remains
within the available stars.

Source: Path instructions

src/components/review/ReviewsShell.tsx (1)

1-1: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

불필요한 use client를 제거해 주세요.

ReviewsShellchildrenReviewTabs를 조합할 뿐 클라이언트 기능을 사용하지 않습니다. 이 파일은 Server Component로 유지하고 ReviewTabs만 클라이언트 경계로 두어 불필요한 클라이언트 번들을 줄이는 편이 좋습니다.

As per path instructions, 불필요한 Client Component와 클라이언트 경계를 추가하지 않아야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/review/ReviewsShell.tsx` at line 1, Remove the "use client"
directive from ReviewsShell so it remains a Server Component. Keep the existing
children and ReviewTabs composition unchanged, allowing only ReviewTabs to
remain the client boundary.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/common/Header/Header.tsx`:
- Around line 168-172: Header의 사용자 표시 영역에서 하드코딩된 "닉네임"을 세션 또는 프로필의 실제 사용자 이름으로
연결하세요. 현재 구조상 사용자 이름을 조회할 수 없다면 해당 텍스트가 임시 값임을 명시하는 TODO 주석을 추가하고, 기존 버튼 및 Text
렌더링은 유지하세요.
- Around line 56-103: Update the keydown handler in the useEffect around
profileMenuRef so ArrowDown, ArrowUp, Home, and End are handled only when
event.target is within the profile menu container; return before preventDefault
for events outside it. Keep Escape handling global while preserving the existing
menu navigation behavior and dependency array.

In `@src/components/review/MyReviewCard.tsx`:
- Around line 27-30: Update the Link element in MyReviewCard by removing
aria-labelledby and retaining the existing aria-label based on displayName, so
the link has a single accessible name.

In `@src/components/review/ReviewTabs.tsx`:
- Around line 20-22: Review the nav element in ReviewTabs and replace the
arbitrary shadow utility shadow-[0_2px_5px_0_rgba(248,248,248,0.1)] with the
matching existing shadow token from tokens.theme.css; if no equivalent token
exists, add that token there first and then reference it through the standard
utility.

In `@src/components/review/ReviewWriteModal.tsx`:
- Line 91: Update the Modal.Close usage in ReviewWriteModal so it remains
mounted while createMutation.isPending, using its supported disabled prop to
prevent closing during submission. Preserve the existing onClose behavior when
the mutation is not pending and keep focus trapped in the modal.
- Around line 84-88: Update ReviewWriteModal so Modal always receives the
onClose function, removing the conditional undefined value. Preserve the
pending-state close prevention by wrapping or guarding ReviewWriteModal’s close
handler when createMutation.isPending, while satisfying Modal’s onClose: () =>
void contract.

In `@src/components/review/WritableReviewCard.tsx`:
- Line 141: Update the move-date rendering in WritableReviewCard around
formatMoveDateLabel so invalid or empty moveDate values cannot throw during
render. Catch the formatter failure or use a safe formatter variant such as
formatMoveDateLabelSafe, and render "-" when formatting fails while preserving
the existing label for valid dates.

In `@src/lib/api/fetchInstance.ts`:
- Around line 165-197: Update requestPaginated to handle res.status === 204
before parsing or returning paginated fields, matching the existing request
behavior and preserving a safe empty-response result. Also reuse or extract the
shared fetch, header, refresh, and error-handling logic between request and
requestPaginated so both paths apply the same 204 handling consistently.

In `@src/lib/api/reviews.ts`:
- Around line 25-30: Update fetchReviewableEstimates and the related review
조회/등록 functions in reviews.ts to use the appropriate API_ROUTES endpoints with
fetchInstance or getPaginated instead of mock helpers and Promise.resolve.
Remove the mock-only branches and preserve each function’s existing return types
while wiring both server retrieval and registration to the real API.

---

Nitpick comments:
In `@src/components/common/Header/Header.tsx`:
- Around line 174-208: Update the profile menu container in the
isProfileMenuOpen rendering to replace the arbitrary min-w-[200px] and
top-[calc(100%+8px)] values with the corresponding spacing tokens from
tokens.theme.css, matching the established dropdown spacing conventions.

In `@src/components/review/ReviewsShell.tsx`:
- Line 1: Remove the "use client" directive from ReviewsShell so it remains a
Server Component. Keep the existing children and ReviewTabs composition
unchanged, allowing only ReviewTabs to remain the client boundary.

In `@src/components/review/ReviewStarRating.tsx`:
- Around line 62-81: Review the star buttons rendered in ReviewStarRating and
implement the WAI-ARIA radiogroup pattern with roving tabindex: keep exactly one
enabled star at tabIndex 0 and assign -1 to the others, then support
ArrowLeft/ArrowRight navigation by moving focus and updating the selected value.
Preserve disabled behavior, aria-checked state, and existing click handling
while ensuring the focused option remains within the available stars.

In `@src/components/review/ReviewWriteModal.tsx`:
- Around line 53-80: Update isSubmitDisabled so it only reflects
createMutation.isPending, allowing handleSubmit to run for invalid rating or
content and display ratingError/contentError. Keep the existing validation and
mutation behavior in handleSubmit unchanged.

In `@src/components/review/WritableReviewsPageClient.tsx`:
- Around line 41-44: Synchronize the writable reviews page state with the
clamped currentPage value so page does not retain an invalid page after the
review list shrinks. Update the pagination logic around handlePageChange and
currentPage to setPage(currentPage) whenever they differ, while preserving
normal navigation behavior and avoiding unnecessary updates.
- Around line 26-39: Use the locally computed totalPages as the single
pagination source: replace pagination.totalPages references in the page controls
with totalPages, remove the buildMockPagination use and its import, and retain
currentPage clamping and pageItems behavior based on the shared totalPages
value.

In `@src/lib/dev-auth.ts`:
- Around line 47-50: In src/lib/dev-auth.ts lines 47-50, define a shared
notifySessionChangeAsync() helper that performs the dynamic session import,
calls notifyAuthSessionChange, and handles failures with catch; replace the
duplicated block with this helper call. Apply the same helper replacement at
lines 60-62, with no separate direct change beyond using the shared helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f320aa8d-ebc7-47bb-b8a0-a2b6512d0d46

📥 Commits

Reviewing files that changed from the base of the PR and between dd5c38b and ab5f3cc.

📒 Files selected for processing (25)
  • src/app/reviews/layout.tsx
  • src/app/reviews/me/page.tsx
  • src/app/reviews/page.tsx
  • src/app/reviews/writable/page.tsx
  • src/components/common/Header/Header.tsx
  • src/components/review/MyReviewCard.tsx
  • src/components/review/MyReviewsPageClient.tsx
  • src/components/review/ReviewEmptyState.tsx
  • src/components/review/ReviewPageFrame.tsx
  • src/components/review/ReviewStarRating.tsx
  • src/components/review/ReviewTabs.tsx
  • src/components/review/ReviewWriteModal.tsx
  • src/components/review/ReviewsShell.tsx
  • src/components/review/WritableReviewCard.tsx
  • src/components/review/WritableReviewsPageClient.tsx
  • src/hooks/useCreateReview.ts
  • src/hooks/useMyReviews.ts
  • src/hooks/useReviewableEstimates.ts
  • src/lib/api/fetchInstance.ts
  • src/lib/api/reviews.ts
  • src/lib/auth/session.ts
  • src/lib/constants/appRoutes.ts
  • src/lib/dev-auth.ts
  • src/lib/mocks/reviews.mock.ts
  • src/types/review.ts

Comment thread src/components/common/Header/Header.tsx Outdated
Comment thread src/components/common/Header/Header.tsx
Comment thread src/components/review/MyReviewCard.tsx
Comment thread src/components/review/ReviewTabs.tsx Outdated
Comment thread src/components/review/ReviewWriteModal.tsx Outdated
Comment thread src/components/review/ReviewWriteModal.tsx Outdated
Comment thread src/components/review/WritableReviewCard.tsx Outdated
Comment thread src/lib/api/fetchInstance.ts
Comment thread src/lib/api/reviews.ts
프로필 메뉴 키 핸들링, 모달 닫기 가드, aria, 탭 shadow 토큰, 날짜/204 방어를 반영합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>

@yooseohyeon yooseohyeon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

확인했습니다! 리뷰가 좀 오래 걸려 죄송합니다!

Comment thread src/components/review/WritableReviewsPageClient.tsx
Comment thread src/components/review/ReviewTabs.tsx
Comment thread src/components/review/ReviewStarRating.tsx
Comment thread src/lib/api/fetchInstance.ts
Comment thread src/components/common/Header/Header.tsx Outdated
등록 실패는 모달 인라인 에러로 표시하고, 별점 a11y role과 헤더 메뉴 타이포를 맞춥니다.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/review/ReviewWriteModal.tsx`:
- Line 85: Reset submitError whenever the user edits the review inputs: add
setSubmitError(undefined) to both the rating and content onChange handlers in
ReviewWriteModal, while preserving their existing update behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a677e31-2846-46ad-bb80-4ea1629eaaed

📥 Commits

Reviewing files that changed from the base of the PR and between 8557d05 and e1f3834.

📒 Files selected for processing (4)
  • src/components/common/Header/Header.tsx
  • src/components/review/ReviewStarRating.tsx
  • src/components/review/ReviewWriteModal.tsx
  • src/components/review/WritableReviewsPageClient.tsx
💤 Files with no reviewable changes (1)
  • src/components/review/WritableReviewsPageClient.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/review/ReviewStarRating.tsx
  • src/components/common/Header/Header.tsx

Comment thread src/components/review/ReviewWriteModal.tsx
제출 실패 후 별점·내용 수정 시 이전 오류 메시지가 남지 않도록 초기화합니다.

Co-authored-by: Cursor <cursoragent@cursor.com>
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