feat: 기사님 이사 완료 로직 추가 - #86
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthrough보낸 견적 상세 화면에 이사 완료 처리를 추가했습니다. 완료 API와 캐시 갱신을 연결했습니다. 상세 화면에 완료 상태와 완료일을 표시합니다. 요청 및 movers 목록은 필터 변경 전에 데이터를 프리패칭합니다. Changes보낸 견적 완료 처리
견적 목록 필터 프리패칭
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SentEstimateDetailPage
participant SentEstimateCompleteAction
participant useCompleteSentEstimate
participant completeSentEstimate
participant ReactQueryCache
SentEstimateDetailPage->>SentEstimateCompleteAction: 완료 액션 렌더링
SentEstimateCompleteAction->>SentEstimateCompleteAction: 확인 모달 표시
SentEstimateCompleteAction->>useCompleteSentEstimate: 완료 mutation 실행
useCompleteSentEstimate->>completeSentEstimate: 견적 완료 PATCH 요청
completeSentEstimate-->>useCompleteSentEstimate: 갱신된 SentEstimate 반환
useCompleteSentEstimate->>ReactQueryCache: 상세 캐시 저장 및 목록 무효화
useCompleteSentEstimate-->>SentEstimateCompleteAction: 성공 또는 오류 상태 전달
SentEstimateCompleteAction-->>SentEstimateDetailPage: 토스트 표시
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)
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. Comment |
juengseulki
left a comment
There was a problem hiding this comment.
📋 PR 리뷰
👍 좋았던 점
- 확정된 보낸 견적에서만 이사 완료 CTA가 노출되도록 상태 조건을 명확하게 적용했습니다.
- 되돌릴 수 없는 상태 변경 전에 확인 모달을 한 번 거치도록 구성했습니다.
- 처리 중에는 CTA와 모달 버튼을 비활성화해 중복 완료 요청을 방지했습니다.
aria-busy와 처리 중 문구를 함께 제공해 비동기 상태 표현도 잘 처리했습니다.- 성공/실패 결과는 공통 Toast 및 API 오류 메시지 처리 방식을 재사용했습니다.
- 완료 API 응답을 상세 Query Cache에 즉시 반영해 화면이 바로 완료 상태로 전환됩니다.
- 보낸 견적 목록 Query도 invalidate해 목록과 상세의 상태 불일치를 방지했습니다.
- 완료된 상세에서는 상태 라벨을
이사완료로 구분했습니다. completedAt이 있을 때만 완료 일시를 표시하도록 처리했습니다.- 완료 시각은
Asia/Seoul기준으로 포맷해 브라우저 환경에 따른 시간 차이를 방지했습니다. - API route도 기존 상수 구조 안에 추가했습니다.
🔍 확인 및 제안
완료 성공 후 상세 캐시는 API 응답으로 즉시 교체하고,
목록은 invalidate하는 방식이라 캐시 동기화 흐름도 적절해 보입니다.
완료된 견적에서는 estimate.status === "COMPLETED"를 기준으로 상태 라벨을 바꾸고,
request.completedAt이 존재할 때 완료 일시를 표시하고 있습니다.
한 가지 작은 UI 제안은,
현재 이사 완료일이라는 label 아래 날짜와 시간이 함께 노출되므로
기획 의도에 따라 이사 완료일시로 맞춰도 좋을 것 같습니다.
그리고 PR 설명에 작성된 다음 항목들은 이번 프론트 diff만으로는 검증할 수 없습니다.
- 기사님 본인의 확정 견적인지 서버 검증
- EstimateRequest 상태가 CONFIRMED → COMPLETED로 변경되는지
- completedAt이 실제 DB에 저장되는지
- 개별 Estimate 상태를 CONFIRMED로 유지하는지
- 완료 후 리뷰 작성 가능 상태로 전환되는지
- 완료 API 소유권 및 상태 검증 테스트
이 부분들은 Backend 완료 API 구현/테스트에서 확인되어야 합니다.
프론트는 해당 완료 API를 PATCH로 호출하고,
반환된 완료 상태를 상세 및 목록에 반영하는 역할은 잘 수행하고 있습니다.
수고하셨습니다! 😊
…into refactor/mover-estimate
…into refactor/mover-estimate
…into refactor/mover-estimate
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/lib/utils/date.ts (2)
90-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKST 오프셋을 이름 있는 상수로 분리해 주세요.
Line 90의
9 * 60 * 60 * 1000은 KST 오프셋을 의미하지만 코드에서 의도가 즉시 드러나지 않습니다.KST_OFFSET_MS같은 모듈 상수로 정의해 사용해 주세요.수정 예시
+const KST_OFFSET_MS = 9 * 60 * 60 * 1000; + - const kstDate = new Date(value.getTime() + 9 * 60 * 60 * 1000); + const kstDate = new Date(value.getTime() + KST_OFFSET_MS);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/utils/date.ts` at line 90, Extract the KST millisecond offset from the inline expression in the kstDate calculation into a module-level named constant such as KST_OFFSET_MS, then use that constant in place of 9 * 60 * 60 * 1000 while preserving the existing date behavior.Source: Path instructions
81-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winKST 자정 경계 테스트를 추가해 주세요.
SentEstimateDetailPage.tsxLine 111-222는 이 함수 결과로CONFIRMED견적의 완료 액션을 노출합니다.YYYY-MM-DD입력에 대해 KST 자정 직전에는false, 자정 시점에는true인지 검증하고, 잘못된 날짜의false동작도 테스트로 고정해 주세요.제공된 downstream context 기준으로,
SentEstimateDetailPage.tsxLine 111-222가isKstDateOnOrAfter결과를 완료 액션 표시 조건에 사용합니다.🤖 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/utils/date.ts` around lines 81 - 95, 다음 날짜의 KST 자정 경계에서 isKstDateOnOrAfter의 결과를 검증하는 테스트를 추가하세요: YYYY-MM-DD 입력에 대해 자정 직전에는 false, 자정 시점에는 true가 되어야 하며, 잘못된 날짜 입력과 잘못된 now 값은 false를 반환해야 합니다. 날짜 생성 시 타임존 의존성을 피하도록 명시적인 Date 값을 사용하고, 기존 함수 동작과 SentEstimateDetailPage의 완료 액션 조건을 보존하세요.
🤖 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.
Nitpick comments:
In `@src/lib/utils/date.ts`:
- Line 90: Extract the KST millisecond offset from the inline expression in the
kstDate calculation into a module-level named constant such as KST_OFFSET_MS,
then use that constant in place of 9 * 60 * 60 * 1000 while preserving the
existing date behavior.
- Around line 81-95: 다음 날짜의 KST 자정 경계에서 isKstDateOnOrAfter의 결과를 검증하는 테스트를 추가하세요:
YYYY-MM-DD 입력에 대해 자정 직전에는 false, 자정 시점에는 true가 되어야 하며, 잘못된 날짜 입력과 잘못된 now 값은
false를 반환해야 합니다. 날짜 생성 시 타임존 의존성을 피하도록 명시적인 Date 값을 사용하고, 기존 함수 동작과
SentEstimateDetailPage의 완료 액션 조건을 보존하세요.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: bda2ffa9-8b3c-46c5-b18c-9eddce66d418
📒 Files selected for processing (2)
src/components/estimate/sent/SentEstimateDetailPage.tsxsrc/lib/utils/date.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/estimate/sent/SentEstimateDetailPage.tsx
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 (2)
src/components/estimate/sent/SentEstimateDetailPage.tsx (2)
39-39: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win완료 상태의 기준 필드를 수정해야 합니다.
제공된 상태 계약에서는 완료 API가
estimateRequest.status를COMPLETED로 변경하고 개별 견적의estimate.status는CONFIRMED로 유지합니다. 현재estimate.status === "COMPLETED"로 라벨을 계산하므로 완료 후에도확정견적이 표시됩니다. 같은 이유로estimate.status === "CONFIRMED"만 검사하는showCompleteAction은 완료 후에도 다시 표시될 수 있습니다.완료 판정은 요청 상태를 사용하고, 액션 조건에는 요청 상태가
CONFIRMED인지 확인하는 조건을 추가해 주세요.수정 예시
-const statusLabel = estimate.status === "COMPLETED" ? "이사완료" : "확정견적"; +const statusLabel = + estimate.estimateRequest.status === "COMPLETED" ? "이사완료" : "확정견적"; const showCompleteAction = - estimate.status === "CONFIRMED" && isKstDateOnOrAfter(request.moveDate); + estimate.status === "CONFIRMED" && + request.status === "CONFIRMED" && + isKstDateOnOrAfter(request.moveDate);Also applies to: 67-67, 137-138
🤖 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/sent/SentEstimateDetailPage.tsx` at line 39, Update the completion checks in SentEstimateDetailPage: derive statusLabel from estimateRequest.status === "COMPLETED" while keeping estimate.status === "CONFIRMED" for the estimate state, and update showCompleteAction to require both estimate.status === "CONFIRMED" and estimateRequest.status === "CONFIRMED".
137-138: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKST 날짜 범위를 현재 서버 기준으로만 보지 마세요.
isKstDateOnOrAfter(request.moveDate)는 현재 시간까지 사용하므로, 이동한 날짜가 이미 KST 기준 지나갔다면 완료 액션이 노출되지 않습니다. 완료 액션은 서버/사용자 입력moveDate의 날짜 범위 기준으로 제어하고, 현재 시간은 별도 조건에서 분리하는 것이 안전합니다.formatKoreanDateTimeWithTime의 UTC → KST 표시는 현재 유틸리티에 맞습니다.🤖 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/sent/SentEstimateDetailPage.tsx` around lines 137 - 138, Update showCompleteAction so its visibility is based on the server/user-provided request.moveDate date range rather than the current KST time; separate any current-time validation into its own condition. Preserve the existing CONFIRMED status requirement and retain formatKoreanDateTimeWithTime’s UTC-to-KST behavior.
🧹 Nitpick comments (3)
src/components/estimate/ReceivedRequestsPage.tsx (2)
51-51: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value페이지 크기 리터럴을 상수로 분리하세요.
10은 목록 조회와 프리패치의 캐시 식별 및 API 요청에 영향을 줍니다. 공유 페이지 크기 상수를 정의하고requestQuery에서 사용하세요.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/estimate/ReceivedRequestsPage.tsx` at line 51, Extract the shared page-size constant from the literal 10 and use it in requestQuery for both the list request and prefetch/cache key paths, ensuring all related pagination behavior remains consistent.Source: Path instructions
70-80: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win현재 query와 같은 프리패치를 건너뛰세요.
onFocus또는onPointerEnter에서 현재 선택된 옵션의 query에 대한prefetchInfiniteQuery가 다시 실행됩니다.prefetchRequests에서nextQuery가requestQuery와 같으면 즉시 반환하고, 동일 key에 대한 중복 호출만 막습니다.🤖 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/ReceivedRequestsPage.tsx` around lines 70 - 80, Update prefetchRequests so it immediately returns when the merged nextQuery is equal to the current requestQuery, preventing redundant prefetchInfiniteQuery calls for the already-selected option while preserving prefetching for changed queries.src/components/estimate/detail/EstimateDetailPageSkeleton.tsx (1)
26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win레이아웃 여백을 디자인 토큰으로 통일해 주세요.
Line 26의
md:pt-[46px]와lg:pt-[43px]는 Tailwind arbitrary value입니다.src/styles/tokens.theme.css에 대응 토큰이 있으면 해당 alias를 사용하고, 없으면 토큰을 추가한 뒤 사용해 주세요.src/components/estimate/sent/SentEstimateDetailPage.tsx와 동일한 여백을 공유하면 로딩 화면과 상세 화면의 정렬 차이도 방지할 수 있습니다.As per path instructions,
src/**/*.{ts,tsx}는src/styles/tokens.theme.css의 디자인 토큰을 사용하고 토큰에 없는 임의 값을 지양해야 합니다.🤖 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/EstimateDetailPageSkeleton.tsx` at line 26, EstimateDetailPageSkeleton의 contentClassName에서 md:pt-[46px]와 lg:pt-[43px]를 제거하고, tokens.theme.css에 대응하는 디자인 토큰 alias를 추가하거나 기존 토큰으로 교체하세요. SentEstimateDetailPage의 동일한 반응형 여백을 재사용해 로딩 화면과 상세 화면의 정렬을 일치시키고, 다른 여백 값은 유지하세요.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.
Outside diff comments:
In `@src/components/estimate/sent/SentEstimateDetailPage.tsx`:
- Line 39: Update the completion checks in SentEstimateDetailPage: derive
statusLabel from estimateRequest.status === "COMPLETED" while keeping
estimate.status === "CONFIRMED" for the estimate state, and update
showCompleteAction to require both estimate.status === "CONFIRMED" and
estimateRequest.status === "CONFIRMED".
- Around line 137-138: Update showCompleteAction so its visibility is based on
the server/user-provided request.moveDate date range rather than the current KST
time; separate any current-time validation into its own condition. Preserve the
existing CONFIRMED status requirement and retain formatKoreanDateTimeWithTime’s
UTC-to-KST behavior.
---
Nitpick comments:
In `@src/components/estimate/detail/EstimateDetailPageSkeleton.tsx`:
- Line 26: EstimateDetailPageSkeleton의 contentClassName에서 md:pt-[46px]와
lg:pt-[43px]를 제거하고, tokens.theme.css에 대응하는 디자인 토큰 alias를 추가하거나 기존 토큰으로 교체하세요.
SentEstimateDetailPage의 동일한 반응형 여백을 재사용해 로딩 화면과 상세 화면의 정렬을 일치시키고, 다른 여백 값은
유지하세요.
In `@src/components/estimate/ReceivedRequestsPage.tsx`:
- Line 51: Extract the shared page-size constant from the literal 10 and use it
in requestQuery for both the list request and prefetch/cache key paths, ensuring
all related pagination behavior remains consistent.
- Around line 70-80: Update prefetchRequests so it immediately returns when the
merged nextQuery is equal to the current requestQuery, preventing redundant
prefetchInfiniteQuery calls for the already-selected option while preserving
prefetching for changed queries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5513aaeb-8db7-41e6-bbd5-bbb9afe799c1
📒 Files selected for processing (8)
src/app/estimate/sent/[estimateId]/loading.tsxsrc/components/common/Checkbox/Checkbox.tsxsrc/components/common/Chip/SelectableChip.tsxsrc/components/common/Select/SelectOption.tsxsrc/components/estimate/ReceivedRequestsPage.tsxsrc/components/estimate/detail/EstimateDetailPageSkeleton.tsxsrc/components/estimate/sent/SentEstimateDetailPage.tsxsrc/components/mover/list/MoversFilters.tsx
📋 작업 내용
🔥 변경 사항
✅ 체크리스트
📷 스크린샷 (선택)
🔗 관련 이슈
Closes #
💬 To Reviewer
Summary by CodeRabbit
새로운 기능
개선