Skip to content

[refactor] 대타 요청 UI 수정#37

Merged
dohy-eon merged 14 commits into
devfrom
refactor/ALT-227
May 20, 2026
Merged

[refactor] 대타 요청 UI 수정#37
dohy-eon merged 14 commits into
devfrom
refactor/ALT-227

Conversation

@dohy-eon
Copy link
Copy Markdown
Member

@dohy-eon dohy-eon commented May 19, 2026

ID

  • ALT-227

변경 내용

  • 알바생 대타 요청 탭·목록/상세 UI 추가 및 11.x API 연동
  • 대타 생성 플로우(매장 선택 → 일정 → 근무 시간 → 요약 → 근무자 → 사유) 구현·UX 보완(피그마 수정사항 반영)

구현 사항

  • API: 보낸/받은 목록·보낸 상세·수락/거절/취소, 교환 가능 스케줄/근무자, 생성 (pageSize 반영)
  • 목록: 보낸/받은 탭, 상태별 섹션, FAB로 생성, targets[].target.workerName 등 상세 응답 정규화
  • 생성 모달: 캘린더(일~토, grid 정렬), 근무 시간 휠 피커 바텀시트(모달 z-[70] 위), 스케줄 없을 때 뒤로가기
  • UI: Navbar showBorder(대타만 구분선 제거), FAB 레이아웃·알바 배지 정렬, 매장 선택 모달 뒤로가기 제거

구현 시연 (필요 시)

2026-05-19.5.56.57.mov

Summary by CodeRabbit

  • New Features

    • 대타 요청 페이지 추가(목록, 상세, 생성 플로우, FAB), 대타 요청 수락/거절(사유 모달)/취소 기능
    • 교환 가능한 스케줄 조회 API 및 캘린더 변환 유틸 추가
    • 대타 관련 컴포넌트: 아바타, 카드, 상세뷰, 리스트 섹션, 스토어 선택 모달, 탭 등 추가
  • UI Improvements

    • 하단 네비게이션에 '대타' 탭 추가 및 탭 렌더링 동적화
    • 월간 캘린더 및 날짜 그리드 레이아웃·정렬 개선
    • 요청 상태 배지·응답 액션 UI 및 Docbar/Hamburger 메뉴 업데이트

Review Change Stack

@dohy-eon dohy-eon requested review from kim3360 and limtjdghks May 19, 2026 08:59
@dohy-eon dohy-eon self-assigned this May 19, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

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

Project Deployment Actions Updated (UTC)
alter-client Ready Ready Preview, Comment May 20, 2026 4:37am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

대타 요청(목록/상세/수락·거절·취소) 기능을 추가하고, 교환 가능 일정 API를 연동해 캘린더 데이터를 서버 기반으로 구성합니다. 캘린더 렌더링을 grid로 리팩토링하고 네비게이션에 substitute 탭을 통합했습니다.

Changes

대타 요청 기능 통합

Layer / File(s) Summary
대타 요청 타입 및 API 계약
src/features/user/substitute/types.ts, src/features/user/substitute/api/*
대타 요청 도메인 타입, API DTO, 페이징·쿼리 파라미터 타입과 수신/발신/액션 API 클라이언트를 추가합니다.
대타 요청 어댑터
src/features/user/substitute/lib/*
API 응답을 UI 모델로 변환하는 어댑터(시간/상태/표시명 포맷, 교환 가능 일정 어댑터)를 추가합니다.
목록·상세 훅
src/features/user/substitute/hooks/*, src/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts
useInfiniteQuery 기반 목록 훅, 상세 훅(accept/reject/cancel 뮤테이션 포함)과 useSubstituteRequestFlow의 서버 기반 전환을 구현합니다.
UI 컴포넌트
src/pages/user/substitute-request/components/*
카드, 배지, 탭, FAB, 아바타, 거절 모달, 스토어 선택 모달, 상세 뷰 등 화면 요소를 추가했습니다.
페이지
src/pages/user/substitute-request/index.tsx
목록/상세 라우팅, 탭 관리, 액션 처리, FAB·스토어 선택·생성 플로우를 통합한 페이지를 추가합니다.

교환 가능 일정 조회 및 캘린더 통합

Layer / File(s) Summary
교환 가능 일정 API 및 어댑터
src/features/user/substitute/api/exchangeableSchedules.ts, src/features/user/substitute/lib/adaptExchangeableSchedules.ts
월 단위 교환 가능 일정을 조회하고 CalendarViewData로 어댑팅합니다.
useSubstituteRequestFlow 서버 전환
src/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts
workspaceId 기반 교환 가능 일정 조회를 도입하고 resolvedCalendarData로 캘린더 선택 로직을 변경합니다. React Query 무효화 대상에 exchangeableSchedulesuserSubstitute.list를 포함합니다.
캘린더 주간 범위·셀 정렬
src/features/home/common/schedule/ui/MonthlyCalendar.tsx, src/features/home/common/schedule/ui/MonthlyDateCell.tsx, src/features/user/home/schedule/lib/date.ts
요일 레이블/셀 스타일을 조정하고 월 경계 계산의 weekStartsOn을 1→0으로 변경합니다. (월→일 기준)

캘린더 UI 개선 (그리드화 및 주간 범위 조정)

Layer / File(s) Summary
ScheduleCalendar 그리드 레이아웃
src/shared/ui/common/ScheduleCalendar.tsx
주간 헤더 및 날짜 그리드를 flex → grid(7열)로 리팩토링하고 셀 크기/정렬을 조정했습니다.
대타 캘린더 피커 그리드·스타일
src/pages/user/workspace-detail/components/SubstituteCalendarPickerPanel.tsx
WEEKDAY_LABELS 공용 상수를 사용하고 DAY_CELL_CLASS/DAY_NUMBER_BASE 상수로 그리드·스타일을 통일했습니다.
대타 모달 흐름 적응
src/pages/user/workspace-detail/components/SubstituteRequestModalFlow.tsx
calendarData를 optional로 변경하고 4단계 버튼 동작을 substituteScheduleId 유무로 분기합니다.

네비게이션 및 라우팅 통합

Layer / File(s) Summary
라우트·탭 확장
src/shared/constants/routes.ts, src/shared/types/tab.ts
ROUTES.USER.SUBSTITUTE_REQUEST 및 상세 패턴을 추가하고 TabKey에 'substitute'를 포함합니다.
Docbar / useDocStore 변경
src/shared/ui/common/Docbar.tsx, src/shared/stores/useDocStore.ts
Docbar를 동적 탭 배열로 전환하고 useDocStore에 substitute 매핑을 추가합니다.
React Query 키 확장
src/shared/lib/queryKeys.ts
workspace.exchangeableSchedules, userSubstitute.list, userSubstitute.sentDetail 키를 추가했습니다.
UI 미세조정
src/shared/ui/common/Navbar.tsx, src/shared/ui/common/HamburgerMenuDrawer.tsx, src/shared/ui/home/WorkerRoleBadge.tsx, storybook/stories/Docbar.stories.tsx
Navbar에 showBorder prop, Hamburger 메뉴 라벨 변경, WorkerRole 타입 분리, Storybook 스토리 확장을 적용했습니다.
WorkspaceDetailPage 정리
src/pages/user/workspace-detail/index.tsx
기존 대타 모달/버튼/상태를 제거했습니다.
앱 라우팅
src/app/App.tsx
SubstituteRequestPage 라우트를 HomeRouteGuard expected="USER"로 추가했습니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • kim3360
  • limtjdghks

시니어 프론트엔드 관점 핵심 이슈(우선순위별)

  1. React Query 무효화 일관성 — High
  • 문제: 훅들에서 invalidateQueries 대상이 문자열 키/파라미터 혼합으로 쓰여 일부 캐시가 갱신되지 않을 수 있음.
  • 조치: 항상 queryKeys helper (queryKeys.workspace.exchangeableSchedules / queryKeys.userSubstitute.list 등)를 사용해 무효화하고, 필요 시 구체 파라미터로 추가 무효화하세요.
  1. calendarData optional화로 인한 널 안정성 — High
  • 문제: calendarData가 optional이 되어 resolvedCalendarData 계산·사용 지점에서 NPE/undefined 참조 위험 존재.
  • 조치: resolvedCalendarData 계산 시 명시적 폴백({ events: [] })을 두고, UI는 빈 상태·로딩·에러 조건을 명확히 처리하세요.
  1. weekStartsOn 변경 영향 범위 — Medium
  • 문제: weekStartsOn이 1→0으로 바뀌면 달력 경계(특히 월말/월초 케이스)에 회귀 가능성 및 다른 컴포넌트와 불일치 발생.
  • 조치: 변경을 전역 상수로 추출해 (WEEK_STARTS_ON) 통일하고, 월경계에 대한 유닛 테스트/스냅샷을 추가하세요.
  1. 상세 fallback(location.state) 의존성 — Medium
  • 문제: received 탭의 상세가 location.state.fallback에 의존하면 새로고침 시 데이터 소실로 UX/에러 발생.
  • 조치: received 상세가 fallback 없을 때 API 재조회 또는 명시적 오류·재시도 UI를 제공하세요.
  1. 접근성: 키보드 포커스·버튼 역할 — Low-Medium
  • 문제: 카드에 role="button"/key handling을 추가한 곳은 좋으나 스크린리더 라벨/aria-pressed 등 추가 고려 필요.
  • 조치: interactive element에 적절한 aria-label/role/keyboard 핸들(이미 처리된 경우 확인)과 포커스 스타일을 보장하세요.

간결한 우선순위 중심 지적은 여기까지입니다.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.42% 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
Title check ✅ Passed PR 제목은 '대타 요청 UI 수정'으로 변경 내용의 일부를 반영하나, 전체적인 주요 변경(API 연동, 생성 플로우 구현, 11.x 지원)을 포괄하지 못해 다소 제한적입니다.
Description check ✅ Passed 필수 섹션(ID, 변경 내용, 구현 사항)이 모두 작성되었으며, 변경의 범위와 의도가 명확합니다. 다만 구현 시연 영상 링크가 제공되었으나 상세 설명은 제한적입니다.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/ALT-227

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
Copy Markdown

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

🧹 Nitpick comments (1)
src/app/App.tsx (1)

25-25: ⚡ Quick win

신규 페이지에 lazy loading 적용을 권장합니다.

SubstituteRequestPage가 일반 import로 추가되어 초기 번들에 포함됩니다. SignupPage처럼 lazy loading을 적용하면 초기 로딩 성능과 번들 크기를 개선할 수 있습니다.

♻️ lazy loading 적용 예시
-import { SubstituteRequestPage } from '`@/pages/user/substitute-request`'
+
+const SubstituteRequestPage = lazy(async () => {
+  const m = await import('`@/pages/user/substitute-request`')
+  return { default: m.SubstituteRequestPage }
+})

그리고 라우트에서 Suspense로 감싸기:

 <Route
   path={ROUTES.USER.SUBSTITUTE_REQUEST_DETAIL_PATTERN}
   element={
     <HomeRouteGuard expected="USER">
-      <SubstituteRequestPage />
+      <Suspense fallback={null}>
+        <SubstituteRequestPage />
+      </Suspense>
     </HomeRouteGuard>
   }
 />
 <Route
   path={ROUTES.USER.SUBSTITUTE_REQUEST}
   element={
     <HomeRouteGuard expected="USER">
-      <SubstituteRequestPage />
+      <Suspense fallback={null}>
+        <SubstituteRequestPage />
+      </Suspense>
     </HomeRouteGuard>
   }
 />
🤖 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/app/App.tsx` at line 25, SubstituteRequestPage is currently imported
eagerly in App.tsx which increases initial bundle size; change the direct import
to a dynamic React.lazy import (e.g., const SubstituteRequestPage =
React.lazy(() => import('`@/pages/user/substitute-request`'))) and remove the
existing eager import, then ensure the route rendering SubstituteRequestPage is
wrapped with React.Suspense (provide a small fallback like a spinner or null) so
the page is lazy-loaded on demand (mirror how SignupPage is implemented).
🤖 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/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts`:
- Around line 7-8: The hook useSubstituteRequestFlow currently imports peer
feature modules getExchangeableSchedules and
adaptExchangeableSchedulesToCalendar directly; remove these direct imports and
instead depend on the substitute feature's public API or shared/entities
contract (e.g., export adapter and API functions from a public index in the
substitute feature or define an interface in shared/entities and implement it in
substitute). Update useSubstituteRequestFlow to call the public API surface (or
injected/consumed service) rather than importing
'`@/features/user/substitute/`...'; ensure the hook references only entities or
shared-layer types and the substitute feature exposes the needed functions via
its public entrypoint.

In
`@src/features/user/substitute/hooks/useUserSubstituteRequestDetailViewModel.ts`:
- Around line 58-75: The mutations currently force a non-null requestId
(requestId!) when calling acceptUserSubstituteRequest,
rejectUserSubstituteRequest, and cancelUserSubstituteRequest, which can trigger
invalid API calls if requestId is undefined; update each useMutation.mutationFn
and any external action handlers to validate requestId first (e.g., return early
or throw a clear error and avoid calling the API) and ensure
options/onActionSuccess is only invoked when requestId is present and the API
call actually occurs; also consider disabling or not registering the mutation
when requestId is null to prevent accidental mutate() calls.

In `@src/features/user/substitute/hooks/useUserSubstituteRequestsViewModel.ts`:
- Line 70: getNextPageParam currently treats an empty string cursor as a valid
next cursor causing hasNextPage to stay true; update the getNextPageParam in
useUserSubstituteRequestsViewModel (the arrow returning
lastPage?.data?.page?.cursor ?? undefined) to return undefined when the cursor
is an empty string (e.g., check for cursor === '' or falsy) so empty cursors are
not considered valid next pages.

In `@src/features/user/substitute/lib/adaptExchangeableSchedules.ts`:
- Around line 1-6: The adapter imports feature-level utilities
(getDurationHours, toDateKey, toTimeLabel) and CalendarViewData from another
feature which violates layer boundaries; refactor by moving those common
utilities/types into the shared or entities layer (or ensure they already exist
there) and update adaptExchangeableSchedules.ts to import getDurationHours,
toDateKey, toTimeLabel and CalendarViewData from the shared/entities module
instead of '`@/features/home/common/`...'; keep the same identifiers
(getDurationHours, toDateKey, toTimeLabel, CalendarViewData) so
adaptExchangeableSchedules logic does not change, and run type checks to ensure
the new import paths are correct.

In `@src/features/user/substitute/types.ts`:
- Line 3: 현재 `src/features/user/substitute/types.ts`가 UI 컴포넌트 모듈의 타입
`WorkerRole`을 직접 임포트하여 도메인 타입이 UI에 결합되어 있습니다; 이 문제를 해결하려면 `WorkerRole` 타입을 비-UI
공통 모듈(예: `shared/types`)으로 이동하고 `WorkerRole`를 해당 모듈에서 export한 뒤
`src/features/user/substitute/types.ts`에서는 그 공통 모듈에서 임포트하도록 변경하세요; 또한
`WorkerRoleBadge` 컴포넌트는 새 위치(`shared/types`)에서 `WorkerRole`을 사용하도록 업데이트(혹은
re-export)하고 공통 타입 파일이 프로젝트에서 접근 가능하도록 index/export 정리를 확인하세요.

In `@src/pages/user/substitute-request/components/SubstituteRequestCard.tsx`:
- Around line 32-65: The root element in SubstituteRequestCard.tsx is a <button>
that contains inner interactive buttons (SubstituteRequestResponseActions),
causing nested interactive-element accessibility violations; change the card
root from a native <button> to a non-interactive container (e.g., <div> or <li>)
with role="button", tabIndex={0}, and keyboard handlers forwarding activation to
the existing onClick handler (handle Enter/Space in onKeyDown or onKeyPress) so
the card remains keyboard-activatable without wrapping native buttons, preserve
inner components (SubstituteRequestResponseActions,
SubstituteRequestStatusBadge, SubstituteProfileAvatar, WorkerRoleBadge) and keep
onAccept/onReject/actionsDisabled intact.

In `@src/pages/user/substitute-request/index.tsx`:
- Around line 56-57: The detail view currently derives its active direction from
the local state directionTab (useState<SubstituteDirectionTab> with initial
'sent'), which causes wrong fetching on direct deep-links/refresh; modify the
logic that chooses the direction for the detail route (where directionTab is
read) to prefer an explicit direction from the route (e.g., path param like
/substitute-request/received/:id or include direction in the detail route), or
restore it from location.state or the DTO payload if present, and only fall back
to the directionTab state if neither route param nor location.state/DTO provides
a direction; update all places that compute direction (the directionTab
setter/reader and wherever fetches use direction, including the blocks
referenced around the current useState and the detail fetch logic) so the
route-provided/restored direction is applied before the local state default.

---

Nitpick comments:
In `@src/app/App.tsx`:
- Line 25: SubstituteRequestPage is currently imported eagerly in App.tsx which
increases initial bundle size; change the direct import to a dynamic React.lazy
import (e.g., const SubstituteRequestPage = React.lazy(() =>
import('`@/pages/user/substitute-request`'))) and remove the existing eager
import, then ensure the route rendering SubstituteRequestPage is wrapped with
React.Suspense (provide a small fallback like a spinner or null) so the page is
lazy-loaded on demand (mirror how SignupPage is implemented).
🪄 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

Run ID: c9e17f79-f405-412c-96e5-6df23a1308bc

📥 Commits

Reviewing files that changed from the base of the PR and between a2321cb and 3647e2c.

⛔ Files ignored due to path filters (1)
  • src/assets/icons/doc/Substitute.svg is excluded by !**/*.svg
📒 Files selected for processing (36)
  • src/app/App.tsx
  • src/features/home/common/schedule/ui/MonthlyCalendar.tsx
  • src/features/home/common/schedule/ui/MonthlyDateCell.tsx
  • src/features/user/home/schedule/lib/date.ts
  • src/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts
  • src/features/user/substitute/api/exchangeableSchedules.ts
  • src/features/user/substitute/api/userSubstituteRequests.ts
  • src/features/user/substitute/hooks/useUserSubstituteRequestDetailViewModel.ts
  • src/features/user/substitute/hooks/useUserSubstituteRequestsViewModel.ts
  • src/features/user/substitute/lib/adaptExchangeableSchedules.ts
  • src/features/user/substitute/lib/adaptUserSubstituteRequest.ts
  • src/features/user/substitute/types.ts
  • src/pages/user/substitute-request/components/SubstituteCreateFab.tsx
  • src/pages/user/substitute-request/components/SubstituteProfileAvatar.tsx
  • src/pages/user/substitute-request/components/SubstituteRejectReasonModal.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestCard.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestDetailView.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestListSections.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestResponseActions.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestStatusBadge.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestTabs.tsx
  • src/pages/user/substitute-request/components/SubstituteStoreSelectModal.tsx
  • src/pages/user/substitute-request/index.tsx
  • src/pages/user/workspace-detail/components/SubstituteCalendarPickerPanel.tsx
  • src/pages/user/workspace-detail/components/SubstituteRequestModalFlow.tsx
  • src/pages/user/workspace-detail/index.tsx
  • src/shared/constants/routes.ts
  • src/shared/lib/queryKeys.ts
  • src/shared/stores/useDocStore.ts
  • src/shared/types/tab.ts
  • src/shared/ui/common/Docbar.tsx
  • src/shared/ui/common/HamburgerMenuDrawer.tsx
  • src/shared/ui/common/Navbar.tsx
  • src/shared/ui/common/ScheduleCalendar.tsx
  • src/shared/ui/home/WorkerRoleBadge.tsx
  • storybook/stories/Docbar.stories.tsx

Comment thread src/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts Outdated
Comment thread src/features/user/substitute/hooks/useUserSubstituteRequestDetailViewModel.ts Outdated
Comment thread src/features/user/substitute/hooks/useUserSubstituteRequestsViewModel.ts Outdated
Comment thread src/features/user/substitute/lib/adaptExchangeableSchedules.ts
Comment thread src/features/user/substitute/types.ts Outdated
Comment thread src/pages/user/substitute-request/components/SubstituteRequestCard.tsx Outdated
Comment thread src/pages/user/substitute-request/index.tsx Outdated
@dohy-eon
Copy link
Copy Markdown
Member Author

@limtjdghks @kim3360 리뷰 부탁드립니다~!

Copy link
Copy Markdown
Member

@limtjdghks limtjdghks left a comment

Choose a reason for hiding this comment

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

고생하셧습니다~

Comment thread src/pages/user/substitute-request/components/SubstituteRejectReasonModal.tsx Outdated
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/pages/user/substitute-request/index.tsx (1)

46-62: 🏗️ Heavy lift

페이지 레이어에 방향 결정 로직이 과도하게 들어와 있습니다.

parseDirectionTab/resolveDetailDirectionTab와 상세 방향 분기 로직은 페이지 조합 책임을 넘어선 비즈니스 규칙입니다. 이 로직은 features/user/substitute 쪽 ViewModel(또는 전용 훅)로 이동하고, 페이지는 결과 상태만 받아 렌더링하도록 분리하는 게 안전합니다.

As per coding guidelines src/pages/**: 페이지 컴포넌트가 비즈니스 로직 없이 조합(Composition)만 하는지.

Also applies to: 84-89, 169-176, 180-190

🤖 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/pages/user/substitute-request/index.tsx` around lines 46 - 62, Move the
direction-parsing and resolution business logic out of the page component into
the substitute feature layer: extract parseDirectionTab and
resolveDetailDirectionTab and the related detail-direction branching (the logic
around locationState?.receivedDto and use of 'sent'/'received' defaults
referenced in lines ~84-89, 169-176, 180-190) into a ViewModel or a dedicated
hook under features/user/substitute (e.g., useSubstituteDirection or
SubstituteViewModel). The page should call that hook/VM to get a resolved
SubstituteDirectionTab and any computed flags, and only render based on the
returned state; remove any remaining conditional direction logic from the page
so it contains composition-only code.
🤖 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/pages/user/substitute-request/index.tsx`:
- Around line 46-62: Move the direction-parsing and resolution business logic
out of the page component into the substitute feature layer: extract
parseDirectionTab and resolveDetailDirectionTab and the related detail-direction
branching (the logic around locationState?.receivedDto and use of
'sent'/'received' defaults referenced in lines ~84-89, 169-176, 180-190) into a
ViewModel or a dedicated hook under features/user/substitute (e.g.,
useSubstituteDirection or SubstituteViewModel). The page should call that
hook/VM to get a resolved SubstituteDirectionTab and any computed flags, and
only render based on the returned state; remove any remaining conditional
direction logic from the page so it contains composition-only code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f23c1c8a-8bcd-49c1-a523-637d51dfca09

📥 Commits

Reviewing files that changed from the base of the PR and between e857d2e and 46ac73d.

📒 Files selected for processing (7)
  • src/features/user/home/workspace/hooks/useSubstituteRequestFlow.ts
  • src/features/user/substitute/hooks/useUserSubstituteRequestDetailViewModel.ts
  • src/features/user/substitute/hooks/useUserSubstituteRequestsViewModel.ts
  • src/features/user/substitute/index.ts
  • src/pages/user/substitute-request/components/SubstituteRejectReasonModal.tsx
  • src/pages/user/substitute-request/components/SubstituteRequestCard.tsx
  • src/pages/user/substitute-request/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/features/user/substitute/index.ts

@dohy-eon
Copy link
Copy Markdown
Member Author

꼬투리 잡지 마

@dohy-eon dohy-eon merged commit 2d32916 into dev May 20, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants