feat: 견적 관리 리팩토링, 지정 기사 표시, 로그인·공유 연동 - #33
Conversation
대기/받은 상세 훅·Actions·Layout을 통합하고, 로딩 UI·pending 훅 네이밍·필터 잔상을 정리한다. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…into refactor/estimate-management Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # src/lib/api/estimateRequest.ts
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough고객 인증 게이트와 인증 기반 조회 제어를 추가하고, 견적 상세 화면을 공통 레이아웃으로 통합했습니다. 공유 기능, 조회 상태, 경로 상수, 지정 기사 표시, 중복 제출 방지와 접근성 속성도 갱신했습니다. Changes고객 인증 및 조회 상태
견적 상세 및 공유
경로 및 보조 동작
Estimated code review effort: 5 (Critical) | ~90 minutes Sequence Diagram(s)sequenceDiagram
participant Customer as 고객 화면
participant CustomerAuthGate
participant useCustomerAuthReady
participant EstimateQuery as 견적 조회 훅
participant API
Customer->>CustomerAuthGate: 화면 진입
CustomerAuthGate->>useCustomerAuthReady: 인증 준비 상태 확인
useCustomerAuthReady-->>CustomerAuthGate: canFetch 반환
CustomerAuthGate->>EstimateQuery: 인증 준비 후 조회 허용
EstimateQuery->>API: 견적 데이터 요청
API-->>EstimateQuery: 견적 데이터 또는 오류
EstimateQuery-->>Customer: 상세·목록 상태 렌더링
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (4)
src/components/auth/CustomerAuthGate.tsx (1)
40-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win기사 전용 리디렉션 경로를
APP_ROUTES로 단일화하세요.동일한 경로가 두 인증 분기에 하드코딩되어 있습니다. 공통 상수를 추가하거나 기존 상수를 사용해 경로 변경 시 불일치를 막아야 합니다.
src/components/auth/CustomerAuthGate.tsx#L40-L42: 문자열 대신 공통 기사 견적 요청 경로 상수를 사용하세요.src/components/estimate/EstimateRequestForm.tsx#L186-L188: 위와 동일한 상수를 사용하세요.As per path instructions, “매직 넘버·매직 스트링을 지양합니다.”
🤖 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/auth/CustomerAuthGate.tsx` around lines 40 - 42, 기사 견적 요청 리디렉션 경로의 중복 하드코딩을 제거하세요. src/components/auth/CustomerAuthGate.tsx 40-42의 isMover 분기와 src/components/estimate/EstimateRequestForm.tsx 186-188의 동일한 리디렉션에서 기존 APP_ROUTES 상수를 재사용하거나 공통 상수를 추가해 사용하고, 두 위치가 동일한 경로를 참조하도록 하세요.Source: Path instructions
src/components/estimate/pending/PendingEstimateDetailView.tsx (1)
27-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift
EstimateDetailView와 거의 동일한 구현입니다 — 데이터 훅·에러 처리·aside 구성까지 중복됩니다.차이는 레이아웃 클래스 값,
price/buttonSize전달,EstimateDetailNotice유무뿐입니다. 두 화면을 하나의 컴포넌트(예:variant="pending" | "received")로 합치거나, 최소한 로딩/에러 분기와 main/aside 구성을 공통 훅·서브컴포넌트로 추출하면 이후 스펙 변경 시 한쪽만 수정되는 문제를 막을 수 있습니다.🤖 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/estimate/pending/PendingEstimateDetailView.tsx` around lines 27 - 88, EstimateDetailView와 중복된 PendingEstimateDetailView 구현을 공통화하세요. 데이터 조회 훅, 로딩·에러 상태 처리, main/aside 구성은 공통 컴포넌트 또는 서브컴포넌트로 추출하고, pending/received 차이는 variant로 전달해 레이아웃 클래스와 price, buttonSize, EstimateDetailNotice 등의 차이만 분기하도록 수정하세요.Source: Path instructions
src/components/estimate/detail/EstimateDetailActions.tsx (1)
65-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value클래스 조합은
cn()으로.삼항으로 전체 클래스 문자열을 중복 작성하고 있어 공통 부분이 어긋날 여지가 있습니다.
♻️ 제안
- <div className={showPrice ? "flex w-full flex-col gap-30" : "flex w-full flex-col gap-12"}> + <div className={cn("flex w-full flex-col", showPrice ? "gap-30" : "gap-12")}>As per path instructions, "클래스 조합은
src/lib/utils/cn.ts의cn()을 사용합니다."🤖 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/estimate/detail/EstimateDetailActions.tsx` at line 65, Update the className on the surrounding div in EstimateDetailActions to use the cn() utility from src/lib/utils/cn.ts, keeping the shared flex, width, and column classes in one base set and conditionally applying only the differing gap class based on showPrice.Source: Path instructions
src/components/estimate/detail/EstimateDetailShare.tsx (1)
107-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win카카오 아이콘은 공용 아이콘으로 교체하고, 페이스북도 재사용될 거면
src/icons로 올려두세요.
src/icons/index.ts에KakaoLoginIcon이 이미 있어서 카카오 아이콘은 로컬 SVG 대신 재사용할 수 있습니다. 페이스북은 공용 아이콘이 없으니, 다른 곳에서도 쓰일 가능성이 있으면 같은 방식으로 분리하는 편이 좋습니다.🤖 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/estimate/detail/EstimateDetailShare.tsx` at line 107, Update EstimateDetailShare’s Kakao share icon to reuse the existing KakaoLoginIcon export from src/icons/index.ts instead of the local KakaoIcon SVG. If the Facebook icon is intended for reuse, extract it into src/icons and consume the shared icon from there.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/estimate/detail/EstimateDetailLayout.tsx`:
- Around line 61-66: Replace the main content wrapper div in
EstimateDetailLayout with a semantic main element so the primary page content is
exposed correctly; preserve its existing className and {main} rendering. Use a
section with an appropriate aria-label only if a main element cannot be used due
to document structure.
In `@src/components/estimate/detail/EstimateDetailShare.tsx`:
- Around line 59-63: Update the iconButtonClassName definition to provide a
minimum 44px touch target on mobile, using min-h-44 and min-w-44 or equivalent
padding while preserving the existing visual icon sizing and current focus,
disabled, and transition classes.
In `@src/components/estimate/detail/EstimateDetailView.tsx`:
- Around line 60-63: Replace the arbitrary pixel utilities in
EstimateDetailView.tsx lines 60-63 with tokens defined by tokens.theme.css, and
introduce or reuse a shared ESTIMATE_DETAIL_LAYOUT_CLASSES preset for the common
detail layout. Update EstimateRequestDetailView.tsx lines 119-122 to consume
that preset instead of duplicating the same class strings; keep both views’
layout behavior consistent.
In `@src/components/estimate/EstimateRequestForm.tsx`:
- Around line 250-253: Remove the ineffective setToastMessage call from the
unauthenticated redirect branch in EstimateRequestForm, or explicitly pass the
message through buildLoginPath and render it on the login screen before
redirecting. Ensure the redirect path remains unchanged when no toast handoff is
implemented.
In `@src/components/estimate/EstimatesQueryStatus.tsx`:
- Around line 19-23: Update the accessibility attributes on the container in
EstimatesQueryStatus so the actionLabel branch using role="alert" does not set
aria-live="polite"; retain aria-live="polite" only for the normal role="status"
branch.
In `@src/lib/share/facebookShare.ts`:
- Line 2: Update POPUP_FEATURES to remove noopener and noreferrer so window.open
returns the popup reference; after opening the window, set popup.opener to null
before the existing success check to preserve opener isolation without causing
the popup result to be null.
---
Nitpick comments:
In `@src/components/auth/CustomerAuthGate.tsx`:
- Around line 40-42: 기사 견적 요청 리디렉션 경로의 중복 하드코딩을 제거하세요.
src/components/auth/CustomerAuthGate.tsx 40-42의 isMover 분기와
src/components/estimate/EstimateRequestForm.tsx 186-188의 동일한 리디렉션에서 기존
APP_ROUTES 상수를 재사용하거나 공통 상수를 추가해 사용하고, 두 위치가 동일한 경로를 참조하도록 하세요.
In `@src/components/estimate/detail/EstimateDetailActions.tsx`:
- Line 65: Update the className on the surrounding div in EstimateDetailActions
to use the cn() utility from src/lib/utils/cn.ts, keeping the shared flex,
width, and column classes in one base set and conditionally applying only the
differing gap class based on showPrice.
In `@src/components/estimate/detail/EstimateDetailShare.tsx`:
- Line 107: Update EstimateDetailShare’s Kakao share icon to reuse the existing
KakaoLoginIcon export from src/icons/index.ts instead of the local KakaoIcon
SVG. If the Facebook icon is intended for reuse, extract it into src/icons and
consume the shared icon from there.
In `@src/components/estimate/pending/PendingEstimateDetailView.tsx`:
- Around line 27-88: EstimateDetailView와 중복된 PendingEstimateDetailView 구현을
공통화하세요. 데이터 조회 훅, 로딩·에러 상태 처리, main/aside 구성은 공통 컴포넌트 또는 서브컴포넌트로 추출하고,
pending/received 차이는 variant로 전달해 레이아웃 클래스와 price, buttonSize,
EstimateDetailNotice 등의 차이만 분기하도록 수정하세요.
🪄 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: 0f959100-613e-4e3d-adbc-08c203a9634f
📒 Files selected for processing (45)
src/app/estimates/page.tsxsrc/components/auth/CustomerAuthGate.tsxsrc/components/common/Header/Header.tsxsrc/components/estimate/EstimateRequestForm.tsxsrc/components/estimate/EstimateRequestSummaryContent.tsxsrc/components/estimate/EstimatesQueryStatus.tsxsrc/components/estimate/EstimatesShell.tsxsrc/components/estimate/RejectedRequestsPage.tsxsrc/components/estimate/detail/EstimateDetailActions.tsxsrc/components/estimate/detail/EstimateDetailLayout.tsxsrc/components/estimate/detail/EstimateDetailShare.tsxsrc/components/estimate/detail/EstimateDetailView.tsxsrc/components/estimate/pending/PendingEstimateCard.tsxsrc/components/estimate/pending/PendingEstimateDetailActions.tsxsrc/components/estimate/pending/PendingEstimateDetailView.tsxsrc/components/estimate/pending/PendingEstimatesPageClient.tsxsrc/components/estimate/received/ReceivedEstimatesPageClient.tsxsrc/components/estimate/requests/EstimateRequestCard.tsxsrc/components/estimate/requests/EstimateRequestDesignatedMovers.tsxsrc/components/estimate/requests/EstimateRequestDetailView.tsxsrc/components/estimate/requests/EstimateRequestsList.tsxsrc/components/estimate/requests/EstimateRequestsPageClient.tsxsrc/components/review/MyReviewsPageClient.tsxsrc/components/review/ReviewsShell.tsxsrc/components/review/WritableReviewsPageClient.tsxsrc/hooks/useCustomerAuthReady.tssrc/hooks/useEstimateDetail.tssrc/hooks/useEstimateRequestDetail.tssrc/hooks/useEstimateRequestList.tssrc/hooks/useMyReviews.tssrc/hooks/usePageShare.tssrc/hooks/usePendingEstimateDetail.tssrc/hooks/usePendingEstimateSections.tssrc/hooks/useReceivedEstimates.tssrc/hooks/useReviewableEstimates.tssrc/lib/api/estimateRequest.tssrc/lib/api/estimateRequests.tssrc/lib/api/pendingEstimates.tssrc/lib/constants/appRoutes.tssrc/lib/kakao/share.tssrc/lib/share/copyLink.tssrc/lib/share/facebookShare.tssrc/lib/share/shareUrl.tssrc/lib/utils/estimateFormat.tssrc/types/kakao.d.ts
💤 Files with no reviewable changes (2)
- src/hooks/usePendingEstimateDetail.ts
- src/components/estimate/pending/PendingEstimateDetailActions.tsx
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/lib/share/facebookShare.ts (1)
11-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift브라우저 부수효과를
src/lib에서 분리해 주세요.이 함수는
window.open()과popup.opener변경으로 브라우저 전역 상태를 직접 변경합니다.src/hooks/usePageShare.ts에서 이미 호출하므로, URL 생성만 순수 함수로src/lib에 남기고 팝업 실행은 훅 또는 전용 클라이언트 어댑터로 이동하는 편이 규칙과 테스트 격리에 맞습니다.As per path instructions,
src/lib/**/*.ts는 순수 함수로 작성하고 부수효과를 두지 않아야 합니다.🤖 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/share/facebookShare.ts` around lines 11 - 25, Refactor openFacebookShare so src/lib retains only a pure Facebook share-URL builder; move window.open and popup.opener mutation into usePageShare or a dedicated client-side adapter. Update callers to perform the browser side effects there while preserving the existing popup failure and boolean-result behavior.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/lib/share/facebookShare.ts`:
- Around line 5-9: Update the return documentation for the Facebook share
function to state that it returns false when running outside a browser or when
the popup cannot be opened, rather than only when a popup is blocked. Keep the
existing implementation unchanged.
In `@src/styles/tokens.theme.css`:
- Around line 217-218: Rename the invalid --spacing-37.5 custom property to
--spacing-37-5, and update the spacing class mapping or references that consume
this token to use the renamed variable consistently.
---
Nitpick comments:
In `@src/lib/share/facebookShare.ts`:
- Around line 11-25: Refactor openFacebookShare so src/lib retains only a pure
Facebook share-URL builder; move window.open and popup.opener mutation into
usePageShare or a dedicated client-side adapter. Update callers to perform the
browser side effects there while preserving the existing popup failure and
boolean-result 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: 8bb7cc8f-3380-4836-93bc-cc82c260e6d6
📒 Files selected for processing (8)
src/components/estimate/EstimateRequestForm.tsxsrc/components/estimate/EstimatesQueryStatus.tsxsrc/components/estimate/detail/EstimateDetailLayout.tsxsrc/components/estimate/detail/EstimateDetailShare.tsxsrc/components/estimate/detail/EstimateDetailView.tsxsrc/components/estimate/requests/EstimateRequestDetailView.tsxsrc/lib/share/facebookShare.tssrc/styles/tokens.theme.css
🚧 Files skipped from review as they are similar to previous changes (3)
- src/components/estimate/detail/EstimateDetailLayout.tsx
- src/components/estimate/detail/EstimateDetailShare.tsx
- src/components/estimate/requests/EstimateRequestDetailView.tsx
…gement Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # src/components/common/Header/Header.tsx # src/components/estimate/request/EstimateRequestForm.tsx # src/lib/constants/appRoutes.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/estimate/request/EstimateRequestForm.tsx (1)
143-166: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift인증 준비가 끝나기 전에는
hasAuthSession()만으로 바로 리다이렉트하지 마세요./estimate-request는CustomerAuthGate밖에서 렌더링되고,hasAuthSession()은 access token만 보므로 refresh 기반 복구 중인 사용자를 로그인으로 보낼 수 있습니다.useCustomerAuthReady같은 준비 상태를 기준으로 리다이렉트와useActiveEstimateRequest활성화를 묶어야 합니다.🤖 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/estimate/request/EstimateRequestForm.tsx` around lines 143 - 166, Update the authentication flow around isLoggedIn, the redirect useEffect, and useActiveEstimateRequest to also consume the customer-auth readiness state, such as useCustomerAuthReady. Only redirect when authentication initialization is complete and no session exists, and enable useActiveEstimateRequest only after readiness is confirmed and the user is authenticated.
🤖 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.
Outside diff comments:
In `@src/components/estimate/request/EstimateRequestForm.tsx`:
- Around line 143-166: Update the authentication flow around isLoggedIn, the
redirect useEffect, and useActiveEstimateRequest to also consume the
customer-auth readiness state, such as useCustomerAuthReady. Only redirect when
authentication initialization is complete and no session exists, and enable
useActiveEstimateRequest only after readiness is confirmed and the user is
authenticated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 12ae5931-92db-4f67-8ee7-22bec842cf6b
📒 Files selected for processing (3)
src/components/common/Header/Header.tsxsrc/components/estimate/request/EstimateRequestForm.tsxsrc/lib/constants/appRoutes.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/constants/appRoutes.ts
Co-authored-by: Cursor <cursoragent@cursor.com>
yooseohyeon
left a comment
There was a problem hiding this comment.
작업하느라 수고하셨습니다! 세션 복구 전에 보호 API가 나가지 않게 Gate랑 canFetch를 이중으로 둔 점, Layout을 공통화하면서도 화면별 간격·Notice는 className이나 분기로 유지한 점 등이 좋았습니다!
공유 기능에서 민감 정보를 제외한 점과 본인만 볼 수 있다는 안내 문구를 추가한 점도 좋았습니다. 공유 링크로 접속하는 사용자의 플로우까지는 고려하지 못했는데, 이 부분은 제가 이후 실제 카카오톡 공유 개능과 통합하는 과정에서 맞추겠습니다!
Co-authored-by: Cursor <cursoragent@cursor.com>
📋 작업 내용
🔥 변경 사항
usePendingEstimateDetail→useEstimateDetail통합,usePendingEstimateSections·pendingEstimates네이밍 정리EstimateDetailLayout/EstimateDetailActions공통화,EstimatesQueryStatus로 로딩·에러 UI 중립화진행 중으로 통일EstimateRequestDesignatedMovers로 지정 요청 대상 기사님(이름·프로필) 표시 (moverId유지)CustomerAuthGate/useCustomerAuthReady로 세션 복구 전 보호 API 호출 차단,TEST_CUSTOMER제거usePageShare+ 카카오 SDK / Facebook sharer / 링크 복사 연동, 소유자 전용 URL은 접근 제한 안내 Toast✅ 체크리스트
📷 스크린샷 (선택)
🔗 관련 이슈
Closes #
💬 To Reviewer
NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY가 필요합니다. 키가 없으면 설정 안내 Toast가 노출됩니다.canFetch), 상세 Layout 공통화가 Figma 간격/Notice 분기를 해치지 않는지, 공유 UX(소유자 전용 안내)가 적절한지Summary by CodeRabbit
새로운 기능
개선 사항