Skip to content

[Feat/#108] 사장님 예약/주문 API 연동#110

Merged
skyblue1232 merged 2 commits into
developfrom
feat/#108/owner-reservation-apis
May 1, 2026
Merged

[Feat/#108] 사장님 예약/주문 API 연동#110
skyblue1232 merged 2 commits into
developfrom
feat/#108/owner-reservation-apis

Conversation

@skyblue1232

@skyblue1232 skyblue1232 commented May 1, 2026

Copy link
Copy Markdown
Contributor

✅ 작업 내용

📝 Description

  • 점장 주문/예약 관리 API 연동
  • 예약/주문 탭 데이터 서버 연동 및 목데이터 제거
  • 예약 수락/거절 mutation 연동
  • 주문 상태값(거래완료/거래취소/환불) UI 반영
  • 거절 사유 입력 validation 추가 (10자 이상 필수)

작업한 내용을 체크해주세요.

  • 예약 목록 조회 API 연동
  • 처리 완료 목록 조회 API 연동
  • 예약 수락/거절 API 연동
  • 주문 상태 UI 반영
  • 거절 사유 validation 적용

🚀 설계 의도 및 개선점

  • mock 데이터 기반 화면을 실제 서버 데이터 기반으로 전환
  • query/mutation 파일을 역할별로 분리해 유지보수성 향상
  • 주문 상태값을 util로 관리해 UI 재사용성 확보
  • 거절 사유 validation을 추가해 잘못된 요청 방지

📸 스크린샷 (선택)

  • 주문 현황 화면
  • 예약 수락/거절 모달

📎 기타 참고사항

  • TanStack Query 기반 query/mutation 적용
  • owner token(localStorage) 기반 인증 테스트 완료

Fixes #108

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 예약 상태에 "환불" 상태 추가
    • 서버 기반 주문 데이터 실시간 동기화
  • 버그 수정

    • 주문 거절 사유 입력 검증 강화 (최소 10자 이상 필수)
    • 주문 거절 시 사유 정보 저장 추가

@skyblue1232 skyblue1232 self-assigned this May 1, 2026
@skyblue1232 skyblue1232 added feat 기능 구현 및 생성 chore 자잘한 수정 api 서버 - 클라이언트 통신 labels May 1, 2026
@vercel

vercel Bot commented May 1, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
compasser-customer Ready Ready Preview, Comment May 1, 2026 9:36am
compasser-owner Ready Ready Preview, Comment May 1, 2026 9:36am

@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown
📝 Walkthrough

개요

주문 관리 기능이 로컬 상태에서 서버 기반 쿼리와 뮤테이션으로 마이그레이션되었습니다. 거부 사유 입력 검증이 추가되었고, 예약 상태 타입에 "refunded" 상태가 추가되었으며, API 모델이 업데이트되었습니다.

변경 사항

Cohort / File(s) 요약
거부 모달 입력 검증
apps/owner/src/app/(tabs)/order/_components/modal/RejectOrderModal.tsx
거부 사유 입력에 최소 10자 요구사항 추가, 공백 정규화, 조건부 확인 버튼 비활성화, 유효하지 않은 상태에서 에러 메시지 표시
예약 타입 확장
apps/owner/src/app/(tabs)/order/_types/order.ts
ReservationStatus"refunded" 상태 추가, ReservationItem에 선택적 rejectReason 필드 추가
상태 헬퍼 업데이트
apps/owner/src/app/(tabs)/order/_utils/orderStatus.ts
getStatusLabelgetStatusClassName 함수에 "refunded" 상태 지원 추가 (레이블: "환불", 클래스명: "body1-m text-secondary")
서버 기반 데이터 페칭
apps/owner/src/app/(tabs)/order/page.tsx
로컬 상태에서 서버 쿼리 기반으로 전환, 보류 중/처리된 예약을 별도로 페칭, 뮤테이션 기반 승인/거부 처리, 로딩/에러 상태 조건부 렌더링
뮤테이션 훅
apps/owner/src/shared/queries/mutation/owner/useApproveReservationMutation.ts, useRejectReservationMutation.ts
승인 및 거부 뮤테이션을 위한 React Query 훅 추가
쿼리 훅
apps/owner/src/shared/queries/query/owner/usePendingReservationsQuery.ts, useProcessedReservationsQuery.ts
보류 중 및 처리된 예약 조회를 위한 React Query 훅 추가
API 도메인 및 모델 업데이트
packages/api/src/domains/owner.ts, packages/api/src/models/owner.ts
ReservationReqDTOReservationRejectReqDTO 변경, rejectReason 필수화, ReservationDTO의 필드명 변경 (nickName→customerName, price→totalPrice), 불필요한 타임스탬프 필드 제거, ReservationListDTO에서 count 필드 제거

시퀀스 다이어그램

sequenceDiagram
    participant User as 사용자
    participant Page as 주문 페이지
    participant Hook as Query/Mutation 훅
    participant QueryClient as React Query
    participant API as API 서버

    User->>Page: 페이지 진입 (탭 선택)
    Page->>Hook: usePendingReservationsQuery() / useProcessedReservationsQuery()
    Hook->>QueryClient: useQuery 실행
    QueryClient->>API: GET 예약 데이터 요청
    API-->>QueryClient: ReservationListDTO 반환
    QueryClient-->>Hook: 데이터/로딩/에러 상태
    Hook-->>Page: 쿼리 결과
    Page->>Page: 로딩 상태 확인 및 렌더링 결정
    
    alt 데이터 로드 성공
        Page->>Page: ReservationDTO → ReservationItem 변환
        Page->>User: 예약 리스트 표시
    else 로딩 중
        Page->>User: 로딩 상태 표시
    else 에러 발생
        Page->>User: 에러 메시지 표시
    end

    User->>Page: 승인 또는 거부 버튼 클릭
    alt 거부 선택
        Page->>Page: RejectOrderModal 열기
        User->>Page: 거부 사유 입력 (10자 이상)
        Page->>Page: 입력값 검증
        User->>Page: 확인 버튼 클릭
        Page->>Hook: useRejectReservationMutation 실행
    else 승인 선택
        Page->>Hook: useApproveReservationMutation 실행
    end
    
    Hook->>QueryClient: useMutation 실행
    QueryClient->>API: POST/PUT 승인/거부 요청
    API-->>QueryClient: 결과 반환
    QueryClient->>QueryClient: 관련 쿼리 무효화
    Hook-->>Page: 뮤테이션 완료
    Page->>Page: 모달 닫기
    Page->>Page: 쿼리 자동 갱신
    Page->>User: 업데이트된 리스트 표시
Loading

코드 리뷰 예상 난이도

🎯 3 (보통) | ⏱️ ~25분

관련 PR

🐰 열 글자의 거부 사유,
서버 데이터로 부터 흘러오고,
환불 상태 들어오네!
뮤테이션 훅들이 춤을 추며,
주문 관리 더욱 매끄러워졌네! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 PR 제목이 변경사항의 주요 내용을 명확히 반영합니다. 사장님 예약/주문 API 연동이라는 제목이 전체 PR의 핵심 목표와 일치합니다.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat/#108/owner-reservation-apis

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@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: 3

🧹 Nitpick comments (1)
apps/owner/src/app/(tabs)/order/_components/modal/RejectOrderModal.tsx (1)

19-21: ⚡ Quick win

최소 길이 기준값(10)을 상수로 추출해 단일 소스로 관리해주세요.

검증식/플레이스홀더/안내문구에 동일 값이 중복되어 정책 변경 시 불일치 위험이 있습니다.

♻️ 제안 diff
 export default function RejectOrderModal({
   open,
   onClose,
   onConfirm,
 }: RejectOrderModalProps) {
+  const MIN_REJECT_REASON_LENGTH = 10;
   const [reason, setReason] = useState("");

   const trimmedReason = reason.trim();
-  const isValidReason = trimmedReason.length >= 10;
+  const isValidReason = trimmedReason.length >= MIN_REJECT_REASON_LENGTH;
@@
-          placeholder="거절 사유를 입력해주세요. (10자 이상)"
+          placeholder={`거절 사유를 입력해주세요. (${MIN_REJECT_REASON_LENGTH}자 이상)`}
@@
-            거절 사유는 10자 이상 입력해주세요.
+            거절 사유는 {MIN_REJECT_REASON_LENGTH}자 이상 입력해주세요.

Also applies to: 70-70, 82-82

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/`(tabs)/order/_components/modal/RejectOrderModal.tsx
around lines 19 - 21, Extract the numeric min-length "10" into a single exported
constant (e.g., MIN_REASON_LENGTH) and replace the literal usages in the
RejectOrderModal component: use MIN_REASON_LENGTH when computing trimmedReason
validity (isValidReason), when building the textarea placeholder and any
helper/validation messages (references around trimmedReason/isValidReason and
the strings at the other occurrences). Ensure the constant is imported/defined
near the component (or a shared constants module) so all occurrences (including
the other two spots noted) reference the same symbol.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/owner/src/app/`(tabs)/order/page.tsx:
- Around line 147-153: The payload sent to rejectMutation.mutate is using an
incorrect status ("REQUESTED"); update the mutation payload in the
rejectMutation.mutate call so that the body either omits the status field
entirely or sets it to the server-expected value ("REJECTED") instead of
"REQUESTED" (refer to the call using rejectMutation.mutate, the payload object
with reservationId: rejectModal.orderId, and body: { rejectReason: reason }).

In `@packages/api/src/domains/owner.ts`:
- Around line 14-17: The ReservationDecisionParams type allows body to be
optional even though ReservationRejectReqDTO requires rejectReason, causing
potential runtime 4xx when rejectReservation sends body ?? {}; change
ReservationDecisionParams to require body (replace body?:
ReservationRejectReqDTO with body: ReservationRejectReqDTO) and remove the
fallback usage of body ?? {} in rejectReservation so callers must pass a valid
ReservationRejectReqDTO (with rejectReason) and the compiler will enforce it.

In `@packages/api/src/models/owner.ts`:
- Around line 16-19: The ReservationRejectReqDTO currently allows any
ReservationStatus which permits invalid values on reject; update the DTO
definition (ReservationRejectReqDTO) to prevent misuse by either removing the
optional status field entirely or tightening its type to a literal "REJECTED"
(e.g., status?: "REJECTED" or status: "REJECTED") and then adjust callers (such
as the call site in apps/owner/src/app/(tabs)/order/page.tsx that sends status:
"REQUESTED") to stop sending a non-reject status; ensure the DTO and its usages
consistently reflect the chosen approach.

---

Nitpick comments:
In `@apps/owner/src/app/`(tabs)/order/_components/modal/RejectOrderModal.tsx:
- Around line 19-21: Extract the numeric min-length "10" into a single exported
constant (e.g., MIN_REASON_LENGTH) and replace the literal usages in the
RejectOrderModal component: use MIN_REASON_LENGTH when computing trimmedReason
validity (isValidReason), when building the textarea placeholder and any
helper/validation messages (references around trimmedReason/isValidReason and
the strings at the other occurrences). Ensure the constant is imported/defined
near the component (or a shared constants module) so all occurrences (including
the other two spots noted) reference the same symbol.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2808262-87ce-43eb-b247-8c859ce73966

📥 Commits

Reviewing files that changed from the base of the PR and between 67d95d5 and 8eb6b98.

📒 Files selected for processing (10)
  • apps/owner/src/app/(tabs)/order/_components/modal/RejectOrderModal.tsx
  • apps/owner/src/app/(tabs)/order/_types/order.ts
  • apps/owner/src/app/(tabs)/order/_utils/orderStatus.ts
  • apps/owner/src/app/(tabs)/order/page.tsx
  • apps/owner/src/shared/queries/mutation/owner/useApproveReservationMutation.ts
  • apps/owner/src/shared/queries/mutation/owner/useRejectReservationMutation.ts
  • apps/owner/src/shared/queries/query/owner/usePendingReservationsQuery.ts
  • apps/owner/src/shared/queries/query/owner/useProcessedReservationsQuery.ts
  • packages/api/src/domains/owner.ts
  • packages/api/src/models/owner.ts

Comment on lines +147 to +153
rejectMutation.mutate(
{
reservationId: rejectModal.orderId,
body: {
status: "REQUESTED",
rejectReason: reason,
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

거절 요청 payload의 상태값이 잘못되어 있습니다.

Line [151]에서 status: "REQUESTED"를 보내면 거절 요청 의미와 충돌합니다. 이 값은 제거하거나, 서버가 필요로 하면 REJECTED로 맞춰야 합니다.

수정 예시
     rejectMutation.mutate(
       {
         reservationId: rejectModal.orderId,
         body: {
-          status: "REQUESTED",
-          rejectReason: reason,
+          rejectReason: reason.trim(),
         },
       },
📝 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
rejectMutation.mutate(
{
reservationId: rejectModal.orderId,
body: {
status: "REQUESTED",
rejectReason: reason,
},
rejectMutation.mutate(
{
reservationId: rejectModal.orderId,
body: {
rejectReason: reason.trim(),
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/`(tabs)/order/page.tsx around lines 147 - 153, The payload
sent to rejectMutation.mutate is using an incorrect status ("REQUESTED"); update
the mutation payload in the rejectMutation.mutate call so that the body either
omits the status field entirely or sets it to the server-expected value
("REJECTED") instead of "REQUESTED" (refer to the call using
rejectMutation.mutate, the payload object with reservationId:
rejectModal.orderId, and body: { rejectReason: reason }).

Comment on lines 14 to 17
export interface ReservationDecisionParams {
reservationId: number;
body?: ReservationReqDTO;
body?: ReservationRejectReqDTO;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

rejectReason 필수 계약을 타입에서 강제하지 못하고 있습니다.

ReservationRejectReqDTOrejectReason가 필수인데 body가 optional이라 reject 호출이 컴파일 단계에서 통과할 수 있습니다. 현재 rejectReservationbody ?? {}를 전송하므로 런타임 4xx를 유발할 수 있습니다.

🐛 제안 diff
-export interface ReservationDecisionParams {
+export interface ApproveReservationParams {
   reservationId: number;
-  body?: ReservationRejectReqDTO;
+}
+
+export interface RejectReservationParams {
+  reservationId: number;
+  body: ReservationRejectReqDTO;
 }
@@
-    approveReservation: async ({ reservationId }: ReservationDecisionParams) => {
+    approveReservation: async ({ reservationId }: ApproveReservationParams) => {
@@
-    }: ReservationDecisionParams) => {
+    }: RejectReservationParams) => {
       const { data } = await api.privateClient.patch<ReservationResponse>(
         `/owners/my-store/reservations/${reservationId}/reject`,
-        body ?? {},
+        body,
       );
       return data;
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/domains/owner.ts` around lines 14 - 17, The
ReservationDecisionParams type allows body to be optional even though
ReservationRejectReqDTO requires rejectReason, causing potential runtime 4xx
when rejectReservation sends body ?? {}; change ReservationDecisionParams to
require body (replace body?: ReservationRejectReqDTO with body:
ReservationRejectReqDTO) and remove the fallback usage of body ?? {} in
rejectReservation so callers must pass a valid ReservationRejectReqDTO (with
rejectReason) and the compiler will enforce it.

Comment on lines +16 to 19
export interface ReservationRejectReqDTO {
status?: ReservationStatus;
rejectReason?: string;
rejectReason: string;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Reject 요청에서 status 오용 가능성 확인
rg -nP --type ts -C3 'ReservationRejectReqDTO|status:\s*"(REQUESTED|APPROVED|CANCELED|REJECTED)"'

Repository: CUK-Compasser/FE

Length of output: 1775


거절 요청 DTO의 status 타입을 제한해 오용을 방지하세요.

ReservationRejectReqDTOstatus?: ReservationStatus는 거절 API에 부적절한 모든 상태값을 허용합니다. 실제로 apps/owner/src/app/(tabs)/order/page.tsx (Line 151)에서 status: "REQUESTED"를 전달하고 있으며, 이는 거절 시점에 요청 상태를 전송하는 오류입니다. status를 제거하거나 "REJECTED"로 명시적으로 제한하는 것이 안전합니다.

 export interface ReservationRejectReqDTO {
-  status?: ReservationStatus;
   rejectReason: string;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/api/src/models/owner.ts` around lines 16 - 19, The
ReservationRejectReqDTO currently allows any ReservationStatus which permits
invalid values on reject; update the DTO definition (ReservationRejectReqDTO) to
prevent misuse by either removing the optional status field entirely or
tightening its type to a literal "REJECTED" (e.g., status?: "REJECTED" or
status: "REJECTED") and then adjust callers (such as the call site in
apps/owner/src/app/(tabs)/order/page.tsx that sends status: "REQUESTED") to stop
sending a non-reject status; ensure the DTO and its usages consistently reflect
the chosen approach.

@skyblue1232 skyblue1232 merged commit 78f2734 into develop May 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api 서버 - 클라이언트 통신 chore 자잘한 수정 feat 기능 구현 및 생성

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 사장님 예약/주문 관리 API 연동

1 participant