[feat] 알바생 대타요청 UI 구현 및 API 연동#31
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (17)
📝 WalkthroughWalkthrough이 PR은 월간/주간/일일 캘린더에 estimated earnings 표시, 대체 근로자 요청을 위한 5단계 모달 플로우, 무한 스크롤 페이지네이션의 totalCount 기반 개선을 포함합니다. ChangesCalendar UI & Substitute Request Feature Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes 시니어 검토 포인트 (핵심 리스크)🔴 1. workspaceSchedule 정규화의 안전성문제: normalizeWorkspaceShifts/ extractWorkspaceScheduleTotals가 비정상 payload에 대해 조용히 빈값으로 처리해 데이터 손실을 일으킬 수 있음. 🔴 2. Substitute Request Flow 유효성 검증 부족문제: 시간/일자/선택 근로자/사유에 대한 클라이언트 검증이 완전하지 않음(예: start >= end, 빈 reason, 유효한 scheduleId 확인).
🔴 3. Day cell 접근성/행동 일관성문제: 비활성(다음/이전 월) 셀은 시각적으로 버튼처럼 보일 수 있으나 클릭 핸들러가 없음 → 혼동/접근성 문제. MonthlyDateCell은 클릭 가능 여부에 따라 button/div로 바뀜. 🟡 4. totalCount 기반 load-more 정책 불투명문제: LIST_LOAD_MORE_MIN_TOTAL_COUNT = 4 하드코딩. totalCount 추출이 항상 첫 페이지만 참고하는 구현은 페이징 흐름에 따라 부정확할 수 있음. 🟡 5. 통화 포맷 일관성문제: estimatedEarningsText 생성에 toLocaleString('ko-KR') 사용이 환경/로케일에 의존적이고 음수/0 처리 미정의. Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/pages/user/workspace-detail/index.tsx (1)
17-17: ⚡ Quick win조건부 모달을 정적 import해서 초기 번들에 포함되고 있습니다
SubstituteRequestModalFlow는 열릴 때만 필요한데 정적 import라 초기 로드 비용이 증가합니다. 페이지 가이드대로React.lazy+Suspense로 분리하는 게 좋습니다.코드 스플리팅 예시
-import { useEffect, useMemo, useState } from 'react' +import { Suspense, lazy, useEffect, useMemo, useState } from 'react' ... -import { SubstituteRequestModalFlow } from './components/SubstituteRequestModalFlow' +const SubstituteRequestModalFlow = lazy( + () => import('./components/SubstituteRequestModalFlow') +) ... - {substituteFlowOpen ? ( - <SubstituteRequestModalFlow - key={substituteFlowSession} - onClose={() => setSubstituteFlowOpen(false)} - storeName={(storeDisplayName ?? '근무 업장').trim()} - calendarData={calendarData} - initialMonth={baseDate} - workspaceId={Number.isFinite(id) && id > 0 ? id : undefined} - /> - ) : null} + {substituteFlowOpen ? ( + <Suspense fallback={null}> + <SubstituteRequestModalFlow + key={substituteFlowSession} + onClose={() => setSubstituteFlowOpen(false)} + storeName={(storeDisplayName ?? '근무 업장').trim()} + calendarData={calendarData} + initialMonth={baseDate} + workspaceId={Number.isFinite(id) && id > 0 ? id : undefined} + /> + </Suspense> + ) : null}As per coding guidelines "
src/pages/**: React.lazy / Suspense를 통한 코드 스플리팅 적용 여부".Also applies to: 128-137
🤖 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/workspace-detail/index.tsx` at line 17, SubstituteRequestModalFlow is statically imported and should be code-split: replace the top-level import of SubstituteRequestModalFlow with a React.lazy dynamic import (e.g. const SubstituteRequestModalFlow = React.lazy(() => import('./components/SubstituteRequestModalFlow'))), and wrap where the modal is rendered with <Suspense fallback={...}> so it only loads when opened; apply the same React.lazy + Suspense pattern to any other conditionally-used components referenced around the 128-137 block to avoid including them in the initial bundle.
🤖 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/pages/user/workspace-detail/components/SubstituteRequestModalFlow.tsx`:
- Around line 92-192: This component (SubstituteRequestModalFlow) contains too
much business logic (state machine, API queries/mutations, error mapping, and
query invalidation); extract that logic into a reusable hook (e.g.,
useSubstituteRequestFlow) or feature component and leave
SubstituteRequestModalFlow as a composition-only layer. Move state variables
(step, substituteReason, selfIntroduction, substituteCalendarBaseDate,
selectedCalendarDate, startHour/startMin/endHour/endMin, selectedCandidateKeys),
the useMemo selectors (selectedWeekdayLabel, summarySelectedTimeLabel,
substituteScheduleId), the useQuery call for exchangeable workers
(queryKeys.workspace.exchangeableWorkers / getExchangeableWorkers /
refetchExchangeable), and the useMutation substituteRequestMutation
(createSubstituteRequest + onSuccess invalidations) into the new hook, expose
necessary setters and derived values, and update SubstituteRequestModalFlow to
call useSubstituteRequestFlow and only render UI and pass handlers.
- Around line 57-75: pickScheduleIdForSelectedDate currently picks the first
event of the selected day and ignores the selected time, causing wrong
scheduleId for days with multiple shifts; update pickScheduleIdForSelectedDate
to use the full selected Date (including time) to find the matching event in
calendarData.events (e.g., match by comparing selected.getTime() against new
Date(event.startDateTime).getTime() and new Date(event.endDateTime).getTime(),
or by matching formatted time strings used where the selection time is built),
return that event.shiftId if numeric and finite (preserve the existing
Number.isFinite check), and only fall back to the first-event behavior if no
time-match is found; references: pickScheduleIdForSelectedDate,
CalendarViewData.events, DATE_KEY_FORMAT, and the code path that builds the
selection time string.
In `@src/pages/user/workspace-detail/index.tsx`:
- Around line 43-54: The current useEffect that calls fetchNextPage() (watching
storeDisplayName, hasNextPage, isFetchingNextPage, fetchNextPage, id) can
repeatedly trigger continuous page fetches when storeDisplayName is missing;
change it to perform a single supplemental fetch instead of repeated
auto-pagination by adding a one-time guard (e.g., a local ref or state like
hasPerformedSupplementalFetch) or split the logic to call a dedicated
single-item lookup path when id is present but storeDisplayName is missing;
update the effect around useEffect/fetchNextPage to check and set that guard so
fetchNextPage() runs at most once for the missing storeDisplayName case and
preserve existing checks for hasNextPage/isFetchingNextPage/id.
---
Nitpick comments:
In `@src/pages/user/workspace-detail/index.tsx`:
- Line 17: SubstituteRequestModalFlow is statically imported and should be
code-split: replace the top-level import of SubstituteRequestModalFlow with a
React.lazy dynamic import (e.g. const SubstituteRequestModalFlow = React.lazy(()
=> import('./components/SubstituteRequestModalFlow'))), and wrap where the modal
is rendered with <Suspense fallback={...}> so it only loads when opened; apply
the same React.lazy + Suspense pattern to any other conditionally-used
components referenced around the 128-137 block to avoid including them in the
initial bundle.
🪄 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: a0b6022d-0a0a-4383-b86b-a9579cd45b39
⛔ Files ignored due to path filters (1)
src/assets/icons/catppuccin_changelog.svgis excluded by!**/*.svg
📒 Files selected for processing (33)
src/features/home/common/schedule/ui/MonthYearPickerModal.tsxsrc/features/home/common/schedule/ui/MonthlyCalendar.tsxsrc/features/home/common/schedule/ui/MonthlyDateCell.tsxsrc/features/manager/home/hooks/useManagerHomeViewModel.tssrc/features/manager/home/hooks/useWorkspaceWorkersViewModel.tssrc/features/user/home/applied-stores/hooks/useAppliedStoresViewModel.tssrc/features/user/home/schedule/hooks/useDailyCalendarViewModel.tssrc/features/user/home/schedule/hooks/useWeeklyCalendarViewModel.tssrc/features/user/home/schedule/types/dailyCalendar.tssrc/features/user/home/schedule/types/weeklyCalendar.tssrc/features/user/home/schedule/ui/DailyCalendar.tsxsrc/features/user/home/schedule/ui/HomeScheduleCalendar.tsxsrc/features/user/home/schedule/ui/WeeklyCalendar.tsxsrc/features/user/home/workspace/api/exchangeableWorkers.tssrc/features/user/home/workspace/api/substituteRequests.tssrc/features/user/home/workspace/api/workspaceSchedule.tssrc/features/user/home/workspace/hooks/useWorkspaceManagersViewModel.tssrc/features/user/home/workspace/hooks/useWorkspaceWorkersViewModel.tssrc/features/user/home/workspace/hooks/useWorkspacesViewModel.tssrc/features/user/home/workspace/types/exchangeableWorkers.tssrc/features/user/home/workspace/types/substituteRequests.tssrc/features/user/home/workspace/types/workspaceSchedule.tssrc/pages/manager/home/index.tsxsrc/pages/user/applied-stores/index.tsxsrc/pages/user/workspace-detail/components/SubstituteCalendarPickerPanel.tsxsrc/pages/user/workspace-detail/components/SubstituteRequestModalFlow.tsxsrc/pages/user/workspace-detail/index.tsxsrc/pages/user/workspace-members/hooks/useWorkspaceMembers.tssrc/pages/user/workspace/index.tsxsrc/shared/lib/getAxiosErrorMessage.tssrc/shared/lib/listLoadMoreVisibility.tssrc/shared/lib/queryKeys.tssrc/shared/ui/common/Navbar.tsx
There was a problem hiding this comment.
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/pages/user/workspace-detail/hooks/useSubstituteRequestFlow.ts`:
- Around line 71-302: The hook useSubstituteRequestFlow contains business logic
and must be moved out of the pages layer into the feature layer's hooks (create
a hooks file under the appropriate feature and copy useSubstituteRequestFlow
there), then update the feature's index.ts to re-export useSubstituteRequestFlow
as the public API; update all imports in the pages code to import
useSubstituteRequestFlow from the feature index, and fix any relative import
paths inside the moved file (queries, mutations, constants like WEEKDAY_LABELS,
queryKeys, getExchangeableWorkers, createSubstituteRequest, etc.) so they
reference the correct feature/shared modules; run the app/tests to ensure
query/mutation behavior and query invalidation still work after the move.
🪄 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: 2397bcc3-8018-4dde-947f-c8f86e2f57a9
📒 Files selected for processing (7)
src/features/home/common/schedule/lib/date.tssrc/features/manager/home/hooks/useTodaySchedulesViewModel.tssrc/features/manager/home/hooks/useWorkerScheduleManageViewModel.tssrc/pages/manager/worker-schedule/index.tsxsrc/pages/user/workspace-detail/components/SubstituteRequestModalFlow.tsxsrc/pages/user/workspace-detail/hooks/useSubstituteRequestFlow.tssrc/pages/user/workspace-detail/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/pages/user/workspace-detail/index.tsx
ID
변경 내용
구현 사항
구현 시연 (필요 시)
2026-05-11.12.51.16.mov
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항
버그 수정