Conversation
디자인 완료 이후에 나머지 구현 예정
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 45 minutes and 38 seconds. ⌛ 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: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Route & navigation src/app/App.tsx, src/pages/login/index.tsx, src/shared/api/auth.ts, src/shared/ui/common/Docbar.tsx, src/shared/stores/useDocStore.ts |
Moved routes under /user/* and added /manager/* route(s). Updated post-login redirects, docbar paths, and pathname→tab mapping. |
Common schedule (shared) src/features/home/common/schedule/lib/date.ts, .../types/calendarView.ts, .../types/calendarBase.ts, .../types/monthlyCalendar.ts, .../hooks/useMonthlyCalendarViewModel.ts, .../hooks/useMonthlyDateCellsState.ts, .../ui/MonthlyCalendar.tsx, .../ui/MonthlyDateCell.tsx |
Added shared date helpers, calendar view types, and MonthlyCalendar UI + view-model; migrated imports to common schedule paths. |
User schedule reorg & compatibility src/features/home/user/schedule/api/schedule.ts, .../lib/date.ts, .../constants/calendar.ts, .../hooks/*, .../types/*, .../ui/* |
Replaced monthly/weekly/daily APIs with unified getSelfSchedule, changed schedule param shapes, added new view-models/hooks and mapping utilities, and added re-exports to preserve previous import paths. |
User workspace feature src/features/home/user/workspace/api/*, .../types/*, .../hooks/*, src/pages/user/workspace/index.tsx, src/pages/user/workspace-detail/index.tsx |
New workspace APIs/adapters, types, hooks/view-models, workspace listing page and workspace detail page with schedule + members lists. |
User applied-stores feature src/features/home/user/applied-stores/api/application.ts, .../types/application.ts, .../types/appliedStore.ts, .../hooks/*, .../ui/*, src/pages/user/applied-stores/index.tsx |
New applied-stores API, types, hooks (including cancel mutation), UI components (list item, detail modal), and page with grouping/filter/pagination. |
Manager APIs/types/hooks/UI src/features/home/manager/api/*, .../types/*, .../hooks/*, .../ui/WorkspaceChangeCard.tsx, src/pages/manager/home/index.tsx, src/pages/manager/worker-schedule/index.tsx |
Added manager API modules (workspaces, workers, postings, schedules, substitutes), DTOs and adapters, view-model hooks (infinite/paginated), manager home page wiring and a worker-schedule management page. |
Shared query keys & hooks refactor src/shared/lib/queryKeys.ts, src/shared/hooks/*, src/shared/api/schedule.ts, src/shared/api/workspaceMembers.ts |
Added centralized queryKeys, removed legacy shared hooks (useSelfScheduleQuery, workspace member query hooks) and deprecated shared schedule API; aliased some old hook names to new view-models. |
State stores src/shared/stores/useWorkspaceStore.ts, removed src/shared/stores/useScheduleStore.ts |
Added persistent workspace store (activeWorkspaceId); removed legacy schedule Zustand store. |
Shared UI updates src/shared/ui/home/WorkerListItem.tsx, src/shared/ui/home/WorkerRoleBadge.tsx, src/shared/ui/manager/*, src/shared/ui/common/Navbar.tsx, src/shared/ui/common/Docbar.tsx |
Moved/added WorkerListItem (home), added owner role, updated manager cards (icons, parsing), and adjusted navbar/docbar styling and route mapping. |
Pages & page wiring src/pages/user/home/index.tsx, src/pages/user/schedule/index.tsx, src/pages/user/workspace-members/*, src/pages/manager/home/index.tsx, src/pages/manager/worker-schedule/index.tsx |
Pages refactored to consume new view-model hooks, updated navigation handlers, removed legacy local stores/hooks, and updated layouts where noted. |
Storybook & config storybook/stories/*, tailwind.config.js |
Updated story import paths to new locations and added main.900 color token. |
Sequence Diagram(s)
sequenceDiagram
participant User
participant ManagerHome as Manager Home Page
participant VM as useManagerHomeViewModel
participant ManagerWSAPI as Manager Workspace API
participant ManagerSchedAPI as Manager Schedule API
participant ManagerWorkersAPI as Manager Workers API
participant ManagerPostingsAPI as Manager Postings API
participant ManagerSubAPI as Manager Substitute API
participant UI as Manager UI
User->>ManagerHome: open page
ManagerHome->>VM: init view model
VM->>ManagerWSAPI: fetch managed workspaces
ManagerWSAPI-->>VM: workspaces
VM->>VM: set activeWorkspaceId
rect rgba(100, 150, 200, 0.5)
VM->>ManagerSchedAPI: fetch monthly schedules (workspaceId, year, month)
ManagerSchedAPI-->>VM: calendar data
end
rect rgba(100, 150, 200, 0.5)
VM->>ManagerWorkersAPI: fetch workspace workers (paged)
ManagerWorkersAPI-->>VM: workers page
end
rect rgba(100, 150, 200, 0.5)
VM->>ManagerPostingsAPI: fetch postings (status=OPEN)
ManagerPostingsAPI-->>VM: postings pages
end
rect rgba(100, 150, 200, 0.5)
VM->>ManagerSubAPI: fetch substitute requests (paged)
ManagerSubAPI-->>VM: substitute pages
end
VM-->>ManagerHome: aggregated data
ManagerHome->>UI: render schedules, workers, postings, substitutes
sequenceDiagram
participant User
participant AppliedPage as Applied Stores Page
participant VM as useAppliedStoresViewModel
participant API as getJobApplications
participant UI as Applied UI Components
User->>AppliedPage: navigate
AppliedPage->>VM: init
VM->>API: fetch page 1 (cursor, status)
API-->>VM: applications page
VM->>VM: group by status
VM-->>AppliedPage: grouped sections
AppliedPage->>UI: render list
User->>UI: click item
UI-->>AppliedPage: open detail modal
User->>UI: click cancel
UI->>VM: useCancelApplication.mutate(id)
VM->>API: PATCH cancel
API-->>VM: success
VM->>VM: invalidate query & refresh
VM-->>UI: close modal / updated list
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
- [feat] 사장님 메인 페이지 #7: Touches route definitions in
src/app/App.tsxand route reorganization overlapping with this PR. - [feat] 근무 스케줄 페이지 구현 #4: Also modifies schedule APIs/hooks and route paths (
/schedule→/user/schedule), overlapping schedule refactor work. - [feat] 근무자 목록 페이지 구현 및 API 연동 #6: Adds/changes workspace-members APIs and pages that this PR refactors/relocates under new workspace feature paths.
Suggested reviewers
- kim3360
- kyeongb-bin
🐰
Hops of code and tidy trails,
Routes rehomed and shared sails,
Calendars hum with common tales,
Features split — the rabbit hails! 🥕✨
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feat/ALT-170
There was a problem hiding this comment.
Actionable comments posted: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (8)
src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts-32-35 (1)
32-35:⚠️ Potential issue | 🟡 MinorReplace placeholder worker identity before release.
Returning a fixed display name (
'이름임') is likely mock data and can surface incorrect user information in production.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts` around lines 32 - 35, The worker object inside useWorkerScheduleManageViewModel currently returns hardcoded mock data (worker.name = '이름임') which must be removed before release; replace the placeholder by wiring the hook to the real identity source (props, context, or auth state) so that the worker object (properties name and role) is populated from the actual user data provider (e.g., currentUser, auth.getUser(), or incoming props) instead of the fixed string, and ensure role remains typed as 'manager' only if that value is derived from the real user record.src/shared/stores/useWorkspaceStore.ts-6-14 (1)
6-14:⚠️ Potential issue | 🟡 MinorAllow resetting
activeWorkspaceIdtonull.The store state supports
null, but the setter API does not. That prevents explicit clearing and can keep stale persisted workspace selection.Suggested fix
interface WorkspaceState { activeWorkspaceId: number | null - setActiveWorkspaceId: (id: number) => void + setActiveWorkspaceId: (id: number | null) => void } @@ - setActiveWorkspaceId: (id: number) => set({ activeWorkspaceId: id }), + setActiveWorkspaceId: (id: number | null) => + set({ activeWorkspaceId: id }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/stores/useWorkspaceStore.ts` around lines 6 - 14, The setter type and implementation for activeWorkspaceId currently only accept a number, preventing clearing to null; update the setActiveWorkspaceId signature to accept number | null and change its implementation inside useWorkspaceStore to call set({ activeWorkspaceId: id }) with id possibly null (so activeWorkspaceId can be explicitly reset), ensuring the persisted store and initial activeWorkspaceId remain compatible with null values.src/features/home/manager/types/posting.ts-84-100 (1)
84-100:⚠️ Potential issue | 🟡 MinorAdd a fallback when mapped weekday labels are empty.
If
workingDayscontains only unknown values, this currently returns''instead of a safe placeholder.🔧 Proposed fix
function formatWorkDays(schedules: PostingScheduleDto[]): string { if (schedules.length === 0) return '-' @@ - return DAY_ORDER.filter(d => daySet.has(d)) - .map(d => WORKING_DAY_KO[d] ?? d) - .join(', ') + const labels = DAY_ORDER.filter(d => daySet.has(d)).map( + d => WORKING_DAY_KO[d] ?? d + ) + return labels.length > 0 ? labels.join(', ') : '-' }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/types/posting.ts` around lines 84 - 100, formatWorkDays currently returns an empty string when schedules contain only unknown weekday values; update the function (formatWorkDays) to compute the mappedLabels from DAY_ORDER.filter(...).map(d => WORKING_DAY_KO[d] ?? d) and if mappedLabels is empty return '-' (same placeholder used when schedules.length === 0), otherwise join and return the labels, ensuring WORKING_DAY_KO lookup is used as before.src/features/home/user/schedule/hooks/useScheduleListViewModel.ts-44-46 (1)
44-46:⚠️ Potential issue | 🟡 MinorReplace the placeholder click handler before shipping.
handleScheduleClickonly logs the id, so the rows look interactive but don't do anything user-facing. Either wire the intended detail/navigation flow or make the item non-interactive until that exists.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/schedule/hooks/useScheduleListViewModel.ts` around lines 44 - 46, handleScheduleClick currently only logs the id making rows appear interactive without behavior; replace the placeholder by wiring the real navigation or callback and/or disabling interactivity until implemented. Update the useScheduleListViewModel hook's handleScheduleClick to call the real navigation or handler (e.g., invoke the router/navigation method or a passed-in onSelectSchedule prop) and pass the schedule id, or change the row rendering to not use onClick/role="button" when handleScheduleClick is a noop so items aren't interactive; ensure you reference and update the handleScheduleClick function in useScheduleListViewModel accordingly.src/features/home/common/schedule/ui/MonthlyCalendar.tsx-53-59 (1)
53-59:⚠️ Potential issue | 🟡 MinorAvoid rendering an interactive button with no action.
This is a clickable affordance with no handler; either wire an action or render non-interactive text.
🔧 Suggested fix (non-interactive variant)
- <button - type="button" - className="flex items-center gap-1 typography-body01-regular text-text-90" - > + <div className="flex items-center gap-1 typography-body01-regular text-text-90"> {monthLabel} <DownIcon className="w-4 h-4" /> - </button> + </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/common/schedule/ui/MonthlyCalendar.tsx` around lines 53 - 59, The button rendering the month label in MonthlyCalendar is an interactive affordance with no handler; either attach an action (e.g., add an onClick/onKeyDown that toggles the month picker or calls a provided prop like onToggleMonthMenu) or make it non-interactive by replacing the <button> with a non-button element (e.g., a <div> or <span>) styled the same and ensuring DownIcon and monthLabel remain present; update the component to use the chosen approach (add handler and accessibility attributes if interactive, or use a semantic non-interactive element if purely decorative) and ensure references to monthLabel and DownIcon stay intact.src/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.ts-39-39 (1)
39-39:⚠️ Potential issue | 🟡 MinorGuard
isLoadingbyenabledcondition to prevent misreporting loading state.TanStack Query v5 returns
isPending: truewhen a query is disabled (enabled: false) and has no cached data. Since this hook disables the query whenworkspaceId <= 0, returning rawisPendingwill incorrectly report loading state even when the query is disabled.🔧 Suggested fix
- isLoading: isPending, + isLoading: workspaceId > 0 && isPending,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.ts` at line 39, The hook currently returns isLoading: isPending which can be true when the query is disabled; update the returned isLoading to be guarded by the query's enabled condition (e.g., use enabled && isPending or enabled ? isPending : false) inside useWorkspaceManagersViewModel so that when workspaceId <= 0 (query disabled) isLoading is always false; locate the enabled flag and isPending returned from the useQuery call in useWorkspaceManagersViewModel and change the returned isLoading accordingly.src/pages/user/home/index.tsx-24-35 (1)
24-35:⚠️ Potential issue | 🟡 MinorStatus mapping conflates different application states in the UI.
The mapping
s.status === 'cancelled' ? 'rejected' : 'applied'treats both 'submitted' and 'accepted' statuses as 'applied'. While the view model correctly groups by all three backend statuses ('submitted', 'accepted', 'cancelled'), the card display loses this distinction for non-rejected applications.Consider whether the UI should preserve the distinction between 'submitted' and 'accepted', or update the type definition to reflect that only two display states exist.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/user/home/index.tsx` around lines 24 - 35, The current mapping in appliedStores collapses 'submitted' and 'accepted' into 'applied' (s.status === 'cancelled' ? 'rejected' : 'applied'), losing important UI state; update the mapping in the useMemo (appliedStores) to map s.status explicitly (e.g., 'cancelled' -> 'rejected', 'accepted' -> 'accepted', 'submitted' -> 'submitted') and then update the AppliedStoreItem type definition to include those display states (or, if you intentionally only want two states, change the type to reflect only 'applied'|'rejected' and keep the explicit mapping). Ensure you update any consumers of AppliedStoreItem (card components) to handle the newly preserved 'submitted' and 'accepted' values if you choose the first option.src/shared/ui/home/WorkerListItem.tsx-81-88 (1)
81-88:⚠️ Potential issue | 🟡 MinorHide the overflow button when no action is provided.
onOptionsis optional, but the component always renders a clickable “더보기” button. In theundefinedcase this becomes a dead control.Proposed fix
- <button - type="button" - onClick={onOptions} - className="shrink-0 rounded cursor-pointer" - aria-label="더보기" - > - <EllipsisIcon /> - </button> + {onOptions ? ( + <button + type="button" + onClick={onOptions} + className="shrink-0 rounded cursor-pointer" + aria-label="더보기" + > + <EllipsisIcon /> + </button> + ) : null}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/home/WorkerListItem.tsx` around lines 81 - 88, The component WorkerListItem always renders the overflow button even when the optional onOptions prop is undefined, creating a dead control; update the rendering logic in WorkerListItem to conditionally render (or return null for) the button containing EllipsisIcon only when onOptions is a function, and ensure accessibility attributes are correct (remove aria-label or mark aria-hidden when not rendered) so no clickable element appears if onOptions is not provided.
🧹 Nitpick comments (19)
src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts (1)
15-29: Constrain day state/actions to valid workday literals.
selectedDays/toggleDaycurrently accept any string, so invalid values can be stored. Tightening to theWORKDAY_OPTIONSunion improves safety.Suggested refactor
const WORKDAY_OPTIONS = ['월', '화', '수', '목', '금', '토', '일'] as const +type Workday = (typeof WORKDAY_OPTIONS)[number] -const DEFAULT_SELECTED_DAYS = ['수', '금'] +const DEFAULT_SELECTED_DAYS: Workday[] = ['수', '금'] export function useWorkerScheduleManageViewModel() { - const [selectedDays, setSelectedDays] = useState<string[]>( + const [selectedDays, setSelectedDays] = useState<Workday[]>( DEFAULT_SELECTED_DAYS ) @@ - function toggleDay(day: string) { + function toggleDay(day: Workday) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts` around lines 15 - 29, selectedDays and toggleDay accept any string; constrain them to the WORKDAY_OPTIONS union to prevent invalid values. Update the state declaration (selectedDays / setSelectedDays) to use the WORKDAY_OPTIONS type (or a derived Workday type) instead of string[], change toggleDay(day: string) to toggleDay(day: Workday) and update any callers to pass only valid WORKDAY_OPTIONS entries, and add a runtime guard inside toggleDay (e.g., check WORKDAY_OPTIONS.includes(day)) before calling setSelectedDays to be defensive; reference DEFAULT_SELECTED_DAYS, WORKDAY_OPTIONS, toggleDay, selectedDays, and setSelectedDays when making these edits.src/features/home/user/workspace/api/workspaceSchedule.ts (1)
2-11: Use the new common schedule module imports in this new file.This API adapter still imports calendar types/date utils from
user/schedule. For newly added code, importing from the common schedule module keeps boundaries cleaner and avoids legacy path coupling.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/api/workspaceSchedule.ts` around lines 2 - 11, The file imports CalendarEvent, CalendarViewData and the date helpers toDateKey, toTimeLabel, getDurationHours, formatScheduleTimeRange from the legacy user/schedule module; update the import statements to pull these types and functions from the new common schedule module instead (replace the existing imports that reference CalendarEvent, CalendarViewData and the four date helper functions), keeping the same symbol names so usages in workspaceSchedule.ts remain unchanged and run the build to verify there are no unresolved imports.src/features/home/user/applied-stores/ui/AppliedStoreList.tsx (1)
27-27: Prefer responsive width guard over hard fixed width.
w-[358px]can overflow in narrower layouts. Considerw-full max-w-[358px]to preserve design width while remaining responsive.💡 Suggested tweak
- <section className="w-[358px] rounded-2xl bg-white py-6"> + <section className="w-full max-w-[358px] rounded-2xl bg-white py-6">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/applied-stores/ui/AppliedStoreList.tsx` at line 27, The section in AppliedStoreList.tsx uses a hard fixed width class "w-[358px]" which can overflow on narrow screens; update the element (the <section> in the AppliedStoreList component) to use a responsive guard by replacing the fixed width with "w-full max-w-[358px]" (i.e., add w-full and max-w-[358px] while keeping the existing rounded-2xl bg-white py-6 classes) so it preserves the design width but remains responsive.src/features/home/user/workspace/ui/WorkingStoresList.tsx (1)
28-28: Prefer responsive width over hard fixed width.Line 28 uses
w-[358px], which can overflow in tighter containers. Considerw-full max-w-[358px]for safer layout behavior.Suggested change
- <section className="w-[358px] rounded-2xl bg-white py-6"> + <section className="w-full max-w-[358px] rounded-2xl bg-white py-6">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/ui/WorkingStoresList.tsx` at line 28, The section in the WorkingStoresList component uses a hard fixed width class "w-[358px]" which can cause overflow; update the section's class to use responsive sizing (e.g., replace "w-[358px]" with "w-full max-w-[358px]") so the container can shrink in tight layouts while keeping the intended maximum width.src/app/App.tsx (1)
65-90: 레거시 경로 리다이렉트 추가를 권장합니다.Line 65 이후 경로가
/user/*로 이동했는데, 기존 북마크/딥링크('/home','/schedule'등) 유입을 위해 alias redirect를 두면 전환이 더 안전합니다.예시 diff
<Route element={<MobileRouteLayoutWithoutDocbar />}> + <Route path="/schedule" element={<Navigate to="/user/schedule" replace />} /> + <Route + path="/workspaces/:workspaceId/members" + element={<Navigate to="/user/workspaces/:workspaceId/members" replace />} + /> <Route path="/user/schedule" element={<SchedulePage />} /> @@ <Route element={<MobileRouteLayoutWithDocbar />}> + <Route path="/home" element={<Navigate to="/user/home" replace />} /> + <Route + path="/job-lookup-map" + element={<Navigate to="/user/job-lookup-map" replace />} + /> <Route path="/user/job-lookup-map" element={<JobLookupMapPage />} /> <Route path="/user/home" element={<UserHomePage />} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/App.tsx` around lines 65 - 90, Add alias redirect Routes for legacy bookmarked paths by adding Route entries that Navigate to the new /user or /manager paths; e.g., add Route path="/home" element={<Navigate to="/user/home" replace />} and path="/schedule" element={<Navigate to="/user/schedule" replace />}, plus aliases like "/workspace" -> "/user/workspace", "/applied-stores" -> "/user/applied-stores", "/job-lookup-map" -> "/user/job-lookup-map" and "/social" -> "/manager/social" (use Navigate components similar to the existing Route with path="/" element={<Navigate ... />}), placing them inside the Router before the final fallback so legacy deep links resolve to the corresponding pages such as UserHomePage, SchedulePage, WorkspacePage, AppliedStoresPage, JobLookupMapPage and SocialPage.src/features/home/manager/api/substitute.ts (1)
18-19: Replace truthy check with explicitundefinedcheck for consistency and safety.Line 18 uses
params.status &&(truthy check) while line 19 usesparams.cursor !== undefined &&(undefined check) on identical optional string fields. For consistency and to prevent accidentally dropping falsy-but-valid values, useparams.status !== undefined &&instead.Current code
...(params.status && { status: params.status }), ...(params.cursor !== undefined && { cursor: params.cursor }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/api/substitute.ts` around lines 18 - 19, The spread that builds the request object uses a truthy check for params.status but an explicit undefined check for params.cursor; update the condition for params.status to use params.status !== undefined (matching the params.cursor check) so falsy-but-valid values (e.g., empty string or 0) are preserved—locate the object spread where ...(params.status && { status: params.status }) is used and replace the condition accordingly.src/shared/ui/manager/SubstituteApprovalCard.tsx (1)
28-33: Replace the new hex literals with design tokens.This card reintroduces hardcoded colors in
statusConfig, the avatar fallback, and the role pill. Please map these to the registered Tailwind tokens so manager UI stays themeable and consistent.Based on learnings, "In the alter-client repository, avoid hardcoding colors in TSX files. Use the Tailwind tokens already registered in tailwind.config.js: use text-sub and border-sub for the color '#3a9982' (sub.DEFAULT), and use bg-bg-dark for '#efefef'. Replace literals like text-[
#3A9982] and bg-[#EFEFEF] with the appropriate tokens in src/pages/manager/home/index.tsx and src/shared/ui/manager/**/*.tsx."Also applies to: 55-75
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/manager/SubstituteApprovalCard.tsx` around lines 28 - 33, The statusConfig object in SubstituteApprovalCard (and related UI pieces: the avatar fallback and the role pill) uses hardcoded hex colors—replace those hex literals (e.g., text-[`#3A9982`], border-[`#3A9982`], bg-[`#EFEFEF`], text-[`#2CE283`], bg-[`#EAFDF3`], text-[`#E28D2C`], bg-[`#FDF8EA`]) with the registered Tailwind tokens so the UI remains themeable: use text-sub and border-sub for the green sub color and bg-bg-dark for the gray background; update the statusConfig entries, the avatar fallback rendering, and the role pill className in SubstituteApprovalCard, and apply the same token replacements in src/pages/manager/home/index.tsx and any files under src/shared/ui/manager/**/*.tsx that still contain hardcoded hexes.src/features/home/common/schedule/ui/MonthlyCalendar.tsx (1)
83-83: Replace hardcoded weekend color with a semantic Tailwind token.Use a design token class instead of
text-[#DC0000]to keep styling consistent and theme-safe.Based on learnings: In the alter-client repository, avoid hardcoding colors in TSX files and use Tailwind tokens already registered in
tailwind.config.js.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/common/schedule/ui/MonthlyCalendar.tsx` at line 83, The component MonthlyCalendar.tsx currently hardcodes the weekend color using 'text-[`#DC0000`]' inside the className conditional; replace that literal color with the semantic Tailwind token used in our design system (for example use the registered token like text-status-error or the appropriate semantic class from tailwind.config.js) so the conditional becomes a semantic class for weekends (index === 5 || index === 6) and retains text-text-50 for others; update the className conditional in the element where index is checked to reference the semantic token instead of the hex color.src/features/home/user/workspace/hooks/useWorkspacesViewModel.ts (1)
37-44: Consider normalizinghasNextPageto boolean for consistency.Other similar hooks in this PR (e.g.,
useWorkspaceWorkersViewModel) normalizehasNextPagewith!!hasNextPage. Returning the raw value here could yieldundefinedinstead offalsewhen there's no next page.Suggested change
return { workspaces, fetchNextPage, - hasNextPage, + hasNextPage: !!hasNextPage, isFetchingNextPage, isLoading, isError, }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/hooks/useWorkspacesViewModel.ts` around lines 37 - 44, The returned hasNextPage in useWorkspacesViewModel may be undefined; normalize it to a boolean like other hooks so callers always get true/false. Update the return object in useWorkspacesViewModel to coerce hasNextPage with !!hasNextPage (matching useWorkspaceWorkersViewModel) so the exported property is consistently boolean.src/pages/user/workspace-detail/index.tsx (2)
24-30: Unusedmodevariable.
modeis destructured from the view model but not used anywhere in the component. Consider removing it from the destructuring if it's not needed, or use it if mode switching is intended.Remove unused variable
const { - mode, baseDate, calendarData, isLoading: scheduleLoading, onDateChange, } = useWorkspaceScheduleViewModel(id)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/user/workspace-detail/index.tsx` around lines 24 - 30, The destructured variable "mode" from useWorkspaceScheduleViewModel(id) is unused; remove "mode" from the destructuring to eliminate the unused variable warning, or if mode switching is intended, wire the returned "mode" into the component's state/JSX logic (e.g., pass it to rendering conditionals or handlers). Locate the call useWorkspaceScheduleViewModel in the component and either delete "mode" from the destructured list or use "mode" where appropriate (e.g., in rendering or effect logic) to reflect the view model's mode.
91-92: EmptyonOptionshandlers are placeholders.These no-op handlers work but suggest incomplete functionality. Consider adding a TODO comment or wiring up the actual behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/user/workspace-detail/index.tsx` around lines 91 - 92, The onOptions prop is currently passed an empty no-op which signals incomplete behavior; update the component instance that sets onOptions to either wire it to a real handler (e.g., implement and pass a function like handleOptions in this module that opens the options menu, navigates, or triggers the intended action) or at minimum replace the empty arrow with a clear TODO comment (e.g., // TODO: implement options handler) so the placeholder is explicit; locate the prop usage named onOptions in this file and connect it to the appropriate handler function or add the TODO inline.src/shared/ui/manager/OngoingPostingCard.tsx (1)
68-74: Replace hardcoded hex colors with Tailwind tokens.Lines 70-71 use hardcoded colors (
#42E590,#EAFDF3) which should be replaced with registered Tailwind tokens. Consider adding these as semantic tokens (e.g.,bg-urgent,bg-urgent-light,text-urgent) intailwind.config.jsif they don't already exist.Example approach
<span className={`inline-flex h-[22px] items-center rounded-[100px] px-2.5 typography-body03-semibold ${ - isUrgent ? 'bg-[`#42E590`] text-white' : 'bg-[`#EAFDF3`] text-[`#42E590`]' + isUrgent ? 'bg-status-urgent text-white' : 'bg-status-urgent-light text-status-urgent' }`} >Then register these colors in
tailwind.config.jsundertheme.extend.colors.Based on learnings: "In the alter-client repository, avoid hardcoding colors in TSX files. Use the Tailwind tokens already registered in tailwind.config.js."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/manager/OngoingPostingCard.tsx` around lines 68 - 74, In OngoingPostingCard.tsx replace the hardcoded hex values in the span className (the conditional branch that uses isUrgent and renders posting.dDay) with Tailwind tokens (e.g., use bg-urgent text-urgent for the urgent branch and bg-urgent-light text-urgent for the non-urgent branch), updating the template literal around isUrgent accordingly; if those tokens don’t exist yet, add semantic color tokens (bg-urgent, bg-urgent-light, text-urgent) under theme.extend.colors in tailwind.config.js and then run the Tailwind build so the new classes are available.src/pages/manager/worker-schedule/index.tsx (1)
63-66: Consider extracting the placeholder avatar pattern.The hardcoded
#ecececin the gradient could be extracted to a reusable component or utility class if this pattern is used elsewhere. Low priority given it's a complex gradient pattern.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/manager/worker-schedule/index.tsx` around lines 63 - 66, Extract the hardcoded gradient avatar placeholder into a reusable component or CSS utility so the color (`#ececec`) can be centralized: create a PlaceholderAvatar React component (or a .placeholder-avatar utility) that renders the div with the repeating-conic-gradient and accepts a prop or CSS variable for the base color, then replace the inline div in the worker-schedule page with <PlaceholderAvatar /> (or apply the .placeholder-avatar class) so the pattern and color are reusable across the app.src/pages/user/applied-stores/index.tsx (1)
34-37: Race condition potential in cancel handler.If
cancelApplicationis called multiple times rapidly (e.g., double-click), theselectedStorereference could become stale or multiple requests could fire. Consider usingisCancellingto disable the button in the modal or debounce the action.♻️ Suggested guard
const handleCancel = () => { - if (!selectedStore) return + if (!selectedStore || isCancelling) return cancelApplication(selectedStore.id, { onSuccess: closeDetail }) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/user/applied-stores/index.tsx` around lines 34 - 37, The cancel handler (handleCancel) can trigger multiple requests if invoked rapidly; add a guard using the cancellation state (e.g., isCancelling or cancelApplication.isLoading) to early-return when a cancellation is already in progress, and ensure the modal/button is disabled while cancelling to prevent double-invocation; update the modal's cancel button to use that disabled state and keep closeDetail called only from the mutation onSuccess so duplicate calls won't race with selectedStore becoming stale.src/features/home/manager/types/substitute.ts (1)
63-68: Date range format may not display correctly for same-day ranges.If
startDateTimeandendDateTimeare on the same day, the output would be redundant (e.g., "4월 16일 ↔ 4월 16일"). Consider handling same-day ranges differently.♻️ Suggested same-day handling
function formatDateRange(startDateTime: string, endDateTime: string): string { const start = new Date(startDateTime) const end = new Date(endDateTime) const fmt = (d: Date) => `${d.getMonth() + 1}월 ${d.getDate()}일` + if (start.toDateString() === end.toDateString()) { + return fmt(start) + } return `${fmt(start)} ↔ ${fmt(end)}` }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/types/substitute.ts` around lines 63 - 68, The formatDateRange function currently renders redundant output when startDateTime and endDateTime fall on the same calendar day (e.g., "4월 16일 ↔ 4월 16일"); update formatDateRange to detect same-day ranges (compare start and end via getFullYear(), getMonth(), and getDate() or use toDateString()) and return a single formatted date string (using the existing fmt(start)) for same-day cases, otherwise keep the existing "start ↔ end" output; update the function signature and maintain the fmt helper and return type string.src/features/home/manager/hooks/useMonthlySchedulesViewModel.ts (1)
16-21: Query key uses fallback0whenworkspaceIdisnull.While
enabled: workspaceId !== nullprevents execution, usingworkspaceId ?? 0in the query key means a transient cache entry is created for workspace ID0before the actual workspace ID is available. This could lead to stale cache entries or unexpected refetch behavior.Consider guarding the query key more explicitly or ensuring consistency:
♻️ Suggested improvement
const { data: rawData, isPending } = useQuery({ - queryKey: queryKeys.manager.schedules(workspaceId ?? 0, year, month), + queryKey: queryKeys.manager.schedules(workspaceId!, year, month), queryFn: () => fetchMonthlySchedules({ workspaceId: workspaceId!, year, month }), enabled: workspaceId !== null, })Since the query is only enabled when
workspaceId !== null, the non-null assertion in the key is safe and ensures the cache key accurately reflects the workspace being queried.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/hooks/useMonthlySchedulesViewModel.ts` around lines 16 - 21, The query key currently uses workspaceId ?? 0 which creates a transient cache entry for 0; update the queryKey to only use the real workspaceId (matching the enabled guard) — e.g. replace queryKeys.manager.schedules(workspaceId ?? 0, year, month) with queryKeys.manager.schedules(workspaceId!, year, month) (or otherwise short-circuit the whole useQuery when workspaceId is null) so the key and enabled: workspaceId !== null are consistent; keep fetchMonthlySchedules and enabled as-is.src/features/home/manager/hooks/useManagerHomeViewModel.ts (1)
10-13: Hardcoded placeholder data for today's workers.
TODAY_WORKERScontains static dummy data. Per the PR description, the "금일 스케줄" API is planned for future implementation.Would you like me to create an issue to track the integration of the today's workers API when it becomes available?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/manager/hooks/useManagerHomeViewModel.ts` around lines 10 - 13, TODAY_WORKERS currently holds hardcoded placeholder data in useManagerHomeViewModel.ts; remove the static entries and replace with an empty array (or initialize from state) and add a clear TODO comment referencing the planned "금일 스케줄" API, then wire the view model to load real data once the API exists (e.g., replace TODAY_WORKERS with a state variable like todayWorkers and a fetchTodayWorkers function to populate it later); ensure you keep the TodayWorkerItem shape so the UI type contract remains valid and create a ticket to track integrating the actual API.src/features/home/user/workspace/api/workspaceMembers.ts (1)
12-42: Consider adding error handling for consistency.Unlike
getSelfScheduleinschedule.tswhich wraps axios calls in try/catch with custom error handling, these API functions propagate errors directly. While TanStack Query handles errors at the hook level, consistent error handling across API modules improves debuggability and error messaging.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/api/workspaceMembers.ts` around lines 12 - 42, Wrap the axios calls in getWorkspaceWorkers and getWorkspaceManagers in a try/catch like getSelfSchedule does: catch Axios errors, normalize/format the error (e.g., extract response.status/message or use the existing handleApiError helper if one exists) and rethrow a consistent Error object or custom ApiError so callers (and logs) get a uniform message; ensure you reference the functions getWorkspaceWorkers and getWorkspaceManagers and maintain returning response.data on success.src/shared/lib/queryKeys.ts (1)
1-7:shared/libis now coupled to a feature API module.Importing
SelfScheduleQueryParamsfrom@/features/home/user/schedule/api/scheduleinverts the dependency direction for the shared layer and makes this utility harder to keep cycle-free. Please move that type to a lower-level types module and import it from both places instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/lib/queryKeys.ts` around lines 1 - 7, The shared util queryKeys currently imports SelfScheduleQueryParams from a feature API which inverts dependencies; extract SelfScheduleQueryParams into a lower-level shared types module (a small types-only file) and re-export it so both the feature API (where the type originated) and this shared/lib/queryKeys import the type from that new module instead of from the feature API; update the import in the queryKeys file to reference the new types module and update the feature API to import the type from the same new module.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/features/home/manager/hooks/useManagedWorkspacesQuery.ts`:
- Around line 22-30: The useEffect in useManagedWorkspacesQuery only guards
against activeWorkspaceId being null but not against a stale persisted id
missing from workspaces; update the effect so it also checks whether
activeWorkspaceId exists in the current workspaces array (e.g.,
find/workspaces.some(w => w.id === activeWorkspaceId)) and if not, compute the
defaultWorkspace (using the existing reduce logic) and call
setActiveWorkspaceId(defaultWorkspace.id); keep the existing early return for
empty workspaces and ensure you reference activeWorkspaceId,
setActiveWorkspaceId, and workspaces in the updated condition.
In `@src/features/home/manager/hooks/useWorkspaceDetailQuery.ts`:
- Around line 8-11: The query key must not coerce null to 0; change the call to
queryKeys.managerWorkspace.detail(...) to pass workspaceId through as nullable
(or a distinct sentinel string) instead of using (workspaceId ?? 0) so the cache
differentiates "no workspace selected" from workspace id 0; update the useQuery
invocation (the queryFn fetchWorkspaceDetail(workspaceId!) can remain guarded by
enabled: workspaceId !== null) and, if necessary, adjust
queryKeys.managerWorkspace.detail to accept number | null (or a string sentinel)
so the key retains the null state.
In `@src/features/home/manager/types/posting.ts`:
- Around line 71-74: The function formatWage currently falls back to the '시급'
label for unknown paymentType values; update it so unknown/added backend enum
values are not misrepresented by removing that default and handling absent
labels explicitly: lookup PAYMENT_TYPE_LABEL[paymentType] (refer to
PAYMENT_TYPE_LABEL and formatWage), if a label exists return `${label}
${amount}원`, otherwise return just `${amount}원` (or a neutral placeholder) so
unknown types are not shown as hourly pay.
In `@src/features/home/manager/types/worker.ts`:
- Around line 1-2: The type StoreWorkerRole is defined in the UI component
StoreWorkerListItem and being imported into the adapter types (worker.ts),
reversing dependencies; extract StoreWorkerRole into a new shared types module
(e.g., create a new module named storeWorkerTypes or similar), export the
StoreWorkerRole type there, update the adapter type file that currently imports
StoreWorkerRole and the UI component StoreWorkerListItem to import
StoreWorkerRole from the new shared module, and remove the UI-layer import from
the adapter so the dependency direction is correct and the build passes.
In `@src/features/home/user/applied-stores/hooks/useAppliedStoresViewModel.ts`:
- Around line 18-23: FILTER_OPTIONS does not include the 'all' option even
though selectedFilter defaults to 'all', so users cannot return to the
unfiltered view; update the FILTER_OPTIONS array (and the identical array used
later around the other occurrence) to include an { key: 'all', label: '전체' }
entry (preferably as the first element) and ensure the FilterType union includes
'all' so the dropdown exposes and accepts that value.
In `@src/features/home/user/applied-stores/types/application.ts`:
- Around line 64-70: FILTER_TO_API_STATUS currently maps the same
ApplicationApiStatus 'ACCEPTED' into both the 'viewed' and 'completed'
FilterType causing duplication and mis-grouping; update the FILTER_TO_API_STATUS
Record so that 'ACCEPTED' only appears in the 'completed' array (remove it from
the 'viewed' array) and scan the other mapping blocks (the other similar mapping
region) to ensure no other duplicate status values exist; adjust any tests or
usages that relied on the old mapping if necessary.
In `@src/features/home/user/schedule/hooks/useScheduleListViewModel.ts`:
- Around line 13-24: The hook currently swallows request failures because it
only returns rawData and isPending; modify the useQuery call in
useScheduleListViewModel to also destructure and return isError and error (e.g.,
const { data: rawData, isPending, isError, error } = useQuery(...)) and add
those two values to the hook's returned object so the consumer can show an error
state instead of treating failures as an empty schedule list; make the same
change for the other useQuery block referenced (lines 48-56) so both schedule
queries expose isError/error.
In `@src/features/home/user/schedule/lib/date.ts`:
- Around line 81-90: getScheduleParamsByMode currently only returns year/month
based on baseDate so weekly views that span month boundaries miss schedules;
modify getScheduleParamsByMode to detect mode === 'weekly', compute the week's
start and end dates (e.g., startOfWeek and endOfWeek relative to baseDate), and
return a range instead of a single month—update SelfScheduleQueryParams to
accept a date range keys like { fromYear, fromMonth, fromDay, toYear, toMonth,
toDay } or { startDate, endDate } so the caller (useWeeklyCalendarViewModel) can
request both months and ensure events in the cross-month week are fetched.
Ensure other callers of getScheduleParamsByMode are updated to handle the new
shape.
In `@src/features/home/user/workspace/api/workspaceSchedule.ts`:
- Around line 83-101: The current loop over sorted shifts can pick a past shift
as the worker's nextShift; update deriveWorkerList so you only consider upcoming
shifts (compare shift.startDateTime or shift.endDateTime to new Date()) before
setting workerMap entries. In practice, inside the loop over sorted, skip shifts
that are entirely in the past and only call formatScheduleTimeRange and set
nextShiftDateTime/nextShiftTimeRange on workerMap for the first future shift per
worker (use the existing sorted, workerMap, formatScheduleTimeRange,
nextShiftDateTime, nextShiftTimeRange identifiers to locate and change the
logic).
In `@src/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.ts`:
- Around line 20-25: The queryKey for the managers query (used in
useWorkspaceManagersViewModel) currently uses only
queryKeys.workspace.managers(workspaceId) which causes different pageSize
callers to share a cache entry; include pageSize in the query key (e.g. add
pageSize as part of the key tuple or pass it into queryKeys.workspace.managers)
so the key uniquely identifies both workspaceId and pageSize, keeping
getWorkspaceManagers pagination caches separate and preventing cross-cursor
collisions.
In `@src/features/home/user/workspace/hooks/useWorkspaceWorkersViewModel.ts`:
- Around line 19-29: The query key used in the useInfiniteQuery call is missing
the pageSize, causing cache collisions; update the queryKey invocation to
include pageSize by calling queryKeys.workspace.workers(workspaceId, pageSize)
so the cache tuple distinguishes different page sizes, leaving the rest of the
useInfiniteQuery config (queryFn, getNextPageParam, enabled) unchanged; locate
the useInfiniteQuery call in useWorkspaceWorkersViewModel and adjust the
queryKey parameter accordingly.
In `@src/pages/login/index.tsx`:
- Around line 22-25: The manager post-login redirect is pointing to the removed
route '/main'; update every place that navigates to '/main' so managers go to
'/manager/home' instead—specifically change the navigate('/main', { replace:
true }) call in the Login page component (scope === 'MANAGER' branch in
src/pages/login/index.tsx) and the corresponding redirect calls in the auth flow
in src/shared/api/auth.ts (the login completion, signup verification, and signup
completion logic that currently use navigate('/main') or return '/main') to use
'/manager/home' so all manager authentication flows land on the correct route.
In `@src/pages/manager/home/index.tsx`:
- Around line 109-131: The WorkspaceChangeList is using a hardcoded
categoryLabel and a noop edit handler and the add button has no click handler;
update WorkspaceChangeList to pass the correct category for each workspace
instead of categoryLabel="카페", replace onEditWorkspace={() => {}} with a real
handler that opens the workspace edit modal (hook or function used elsewhere,
e.g., openEditWorkspaceModal or editWorkspace), ensure selectedWorkspaceId uses
workspaceChangeModal.selectedWorkspaceId, and wire the add button (the element
rendering managerWorkspaceModalPlusIcon) to the workspace creation action (e.g.,
openCreateWorkspaceModal or createWorkspace) or hide the edit/add controls when
those actions are not available.
In `@src/pages/manager/worker-schedule/index.tsx`:
- Around line 160-167: The "저장" button currently has no onClick, so user edits
aren't persisted; add an onClick prop that calls a new handler (e.g.,
handleSave) and wire that handler to the existing save mutation or API call
(e.g., useSaveSchedule / saveSchedule / apiSaveWorkerSchedule) to perform the
persist operation; if the mutation doesn't exist yet, scaffold handleSave to
validate state, call the save API/mutation, handle success/error (show toast or
set error state) and disable the button while saving (or add a TODO comment and
set disabled={true}) so the UI is not misleading.
In `@src/shared/lib/queryKeys.ts`:
- Around line 10-13: The workers and managers query-key factories currently
include cursor and pageSize in their returned stable key which causes per-page
cache entries; update the workers and managers functions in queryKeys.ts to only
accept (workspaceId?: number) and return ['workspace','workers',workspaceId] as
const and ['workspace','managers',workspaceId] as const respectively (remove
cursor and pageSize from both the parameter list and the returned array); keep
the const tuple return and leave pagination cursor handling to pageParam in the
infinite query callers.
---
Minor comments:
In `@src/features/home/common/schedule/ui/MonthlyCalendar.tsx`:
- Around line 53-59: The button rendering the month label in MonthlyCalendar is
an interactive affordance with no handler; either attach an action (e.g., add an
onClick/onKeyDown that toggles the month picker or calls a provided prop like
onToggleMonthMenu) or make it non-interactive by replacing the <button> with a
non-button element (e.g., a <div> or <span>) styled the same and ensuring
DownIcon and monthLabel remain present; update the component to use the chosen
approach (add handler and accessibility attributes if interactive, or use a
semantic non-interactive element if purely decorative) and ensure references to
monthLabel and DownIcon stay intact.
In `@src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts`:
- Around line 32-35: The worker object inside useWorkerScheduleManageViewModel
currently returns hardcoded mock data (worker.name = '이름임') which must be
removed before release; replace the placeholder by wiring the hook to the real
identity source (props, context, or auth state) so that the worker object
(properties name and role) is populated from the actual user data provider
(e.g., currentUser, auth.getUser(), or incoming props) instead of the fixed
string, and ensure role remains typed as 'manager' only if that value is derived
from the real user record.
In `@src/features/home/manager/types/posting.ts`:
- Around line 84-100: formatWorkDays currently returns an empty string when
schedules contain only unknown weekday values; update the function
(formatWorkDays) to compute the mappedLabels from DAY_ORDER.filter(...).map(d =>
WORKING_DAY_KO[d] ?? d) and if mappedLabels is empty return '-' (same
placeholder used when schedules.length === 0), otherwise join and return the
labels, ensuring WORKING_DAY_KO lookup is used as before.
In `@src/features/home/user/schedule/hooks/useScheduleListViewModel.ts`:
- Around line 44-46: handleScheduleClick currently only logs the id making rows
appear interactive without behavior; replace the placeholder by wiring the real
navigation or callback and/or disabling interactivity until implemented. Update
the useScheduleListViewModel hook's handleScheduleClick to call the real
navigation or handler (e.g., invoke the router/navigation method or a passed-in
onSelectSchedule prop) and pass the schedule id, or change the row rendering to
not use onClick/role="button" when handleScheduleClick is a noop so items aren't
interactive; ensure you reference and update the handleScheduleClick function in
useScheduleListViewModel accordingly.
In `@src/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.ts`:
- Line 39: The hook currently returns isLoading: isPending which can be true
when the query is disabled; update the returned isLoading to be guarded by the
query's enabled condition (e.g., use enabled && isPending or enabled ? isPending
: false) inside useWorkspaceManagersViewModel so that when workspaceId <= 0
(query disabled) isLoading is always false; locate the enabled flag and
isPending returned from the useQuery call in useWorkspaceManagersViewModel and
change the returned isLoading accordingly.
In `@src/pages/user/home/index.tsx`:
- Around line 24-35: The current mapping in appliedStores collapses 'submitted'
and 'accepted' into 'applied' (s.status === 'cancelled' ? 'rejected' :
'applied'), losing important UI state; update the mapping in the useMemo
(appliedStores) to map s.status explicitly (e.g., 'cancelled' -> 'rejected',
'accepted' -> 'accepted', 'submitted' -> 'submitted') and then update the
AppliedStoreItem type definition to include those display states (or, if you
intentionally only want two states, change the type to reflect only
'applied'|'rejected' and keep the explicit mapping). Ensure you update any
consumers of AppliedStoreItem (card components) to handle the newly preserved
'submitted' and 'accepted' values if you choose the first option.
In `@src/shared/stores/useWorkspaceStore.ts`:
- Around line 6-14: The setter type and implementation for activeWorkspaceId
currently only accept a number, preventing clearing to null; update the
setActiveWorkspaceId signature to accept number | null and change its
implementation inside useWorkspaceStore to call set({ activeWorkspaceId: id })
with id possibly null (so activeWorkspaceId can be explicitly reset), ensuring
the persisted store and initial activeWorkspaceId remain compatible with null
values.
In `@src/shared/ui/home/WorkerListItem.tsx`:
- Around line 81-88: The component WorkerListItem always renders the overflow
button even when the optional onOptions prop is undefined, creating a dead
control; update the rendering logic in WorkerListItem to conditionally render
(or return null for) the button containing EllipsisIcon only when onOptions is a
function, and ensure accessibility attributes are correct (remove aria-label or
mark aria-hidden when not rendered) so no clickable element appears if onOptions
is not provided.
---
Nitpick comments:
In `@src/app/App.tsx`:
- Around line 65-90: Add alias redirect Routes for legacy bookmarked paths by
adding Route entries that Navigate to the new /user or /manager paths; e.g., add
Route path="/home" element={<Navigate to="/user/home" replace />} and
path="/schedule" element={<Navigate to="/user/schedule" replace />}, plus
aliases like "/workspace" -> "/user/workspace", "/applied-stores" ->
"/user/applied-stores", "/job-lookup-map" -> "/user/job-lookup-map" and
"/social" -> "/manager/social" (use Navigate components similar to the existing
Route with path="/" element={<Navigate ... />}), placing them inside the Router
before the final fallback so legacy deep links resolve to the corresponding
pages such as UserHomePage, SchedulePage, WorkspacePage, AppliedStoresPage,
JobLookupMapPage and SocialPage.
In `@src/features/home/common/schedule/ui/MonthlyCalendar.tsx`:
- Line 83: The component MonthlyCalendar.tsx currently hardcodes the weekend
color using 'text-[`#DC0000`]' inside the className conditional; replace that
literal color with the semantic Tailwind token used in our design system (for
example use the registered token like text-status-error or the appropriate
semantic class from tailwind.config.js) so the conditional becomes a semantic
class for weekends (index === 5 || index === 6) and retains text-text-50 for
others; update the className conditional in the element where index is checked
to reference the semantic token instead of the hex color.
In `@src/features/home/manager/api/substitute.ts`:
- Around line 18-19: The spread that builds the request object uses a truthy
check for params.status but an explicit undefined check for params.cursor;
update the condition for params.status to use params.status !== undefined
(matching the params.cursor check) so falsy-but-valid values (e.g., empty string
or 0) are preserved—locate the object spread where ...(params.status && {
status: params.status }) is used and replace the condition accordingly.
In `@src/features/home/manager/hooks/useManagerHomeViewModel.ts`:
- Around line 10-13: TODAY_WORKERS currently holds hardcoded placeholder data in
useManagerHomeViewModel.ts; remove the static entries and replace with an empty
array (or initialize from state) and add a clear TODO comment referencing the
planned "금일 스케줄" API, then wire the view model to load real data once the API
exists (e.g., replace TODAY_WORKERS with a state variable like todayWorkers and
a fetchTodayWorkers function to populate it later); ensure you keep the
TodayWorkerItem shape so the UI type contract remains valid and create a ticket
to track integrating the actual API.
In `@src/features/home/manager/hooks/useMonthlySchedulesViewModel.ts`:
- Around line 16-21: The query key currently uses workspaceId ?? 0 which creates
a transient cache entry for 0; update the queryKey to only use the real
workspaceId (matching the enabled guard) — e.g. replace
queryKeys.manager.schedules(workspaceId ?? 0, year, month) with
queryKeys.manager.schedules(workspaceId!, year, month) (or otherwise
short-circuit the whole useQuery when workspaceId is null) so the key and
enabled: workspaceId !== null are consistent; keep fetchMonthlySchedules and
enabled as-is.
In `@src/features/home/manager/hooks/useWorkerScheduleManageViewModel.ts`:
- Around line 15-29: selectedDays and toggleDay accept any string; constrain
them to the WORKDAY_OPTIONS union to prevent invalid values. Update the state
declaration (selectedDays / setSelectedDays) to use the WORKDAY_OPTIONS type (or
a derived Workday type) instead of string[], change toggleDay(day: string) to
toggleDay(day: Workday) and update any callers to pass only valid
WORKDAY_OPTIONS entries, and add a runtime guard inside toggleDay (e.g., check
WORKDAY_OPTIONS.includes(day)) before calling setSelectedDays to be defensive;
reference DEFAULT_SELECTED_DAYS, WORKDAY_OPTIONS, toggleDay, selectedDays, and
setSelectedDays when making these edits.
In `@src/features/home/manager/types/substitute.ts`:
- Around line 63-68: The formatDateRange function currently renders redundant
output when startDateTime and endDateTime fall on the same calendar day (e.g.,
"4월 16일 ↔ 4월 16일"); update formatDateRange to detect same-day ranges (compare
start and end via getFullYear(), getMonth(), and getDate() or use
toDateString()) and return a single formatted date string (using the existing
fmt(start)) for same-day cases, otherwise keep the existing "start ↔ end"
output; update the function signature and maintain the fmt helper and return
type string.
In `@src/features/home/user/applied-stores/ui/AppliedStoreList.tsx`:
- Line 27: The section in AppliedStoreList.tsx uses a hard fixed width class
"w-[358px]" which can overflow on narrow screens; update the element (the
<section> in the AppliedStoreList component) to use a responsive guard by
replacing the fixed width with "w-full max-w-[358px]" (i.e., add w-full and
max-w-[358px] while keeping the existing rounded-2xl bg-white py-6 classes) so
it preserves the design width but remains responsive.
In `@src/features/home/user/workspace/api/workspaceMembers.ts`:
- Around line 12-42: Wrap the axios calls in getWorkspaceWorkers and
getWorkspaceManagers in a try/catch like getSelfSchedule does: catch Axios
errors, normalize/format the error (e.g., extract response.status/message or use
the existing handleApiError helper if one exists) and rethrow a consistent Error
object or custom ApiError so callers (and logs) get a uniform message; ensure
you reference the functions getWorkspaceWorkers and getWorkspaceManagers and
maintain returning response.data on success.
In `@src/features/home/user/workspace/api/workspaceSchedule.ts`:
- Around line 2-11: The file imports CalendarEvent, CalendarViewData and the
date helpers toDateKey, toTimeLabel, getDurationHours, formatScheduleTimeRange
from the legacy user/schedule module; update the import statements to pull these
types and functions from the new common schedule module instead (replace the
existing imports that reference CalendarEvent, CalendarViewData and the four
date helper functions), keeping the same symbol names so usages in
workspaceSchedule.ts remain unchanged and run the build to verify there are no
unresolved imports.
In `@src/features/home/user/workspace/hooks/useWorkspacesViewModel.ts`:
- Around line 37-44: The returned hasNextPage in useWorkspacesViewModel may be
undefined; normalize it to a boolean like other hooks so callers always get
true/false. Update the return object in useWorkspacesViewModel to coerce
hasNextPage with !!hasNextPage (matching useWorkspaceWorkersViewModel) so the
exported property is consistently boolean.
In `@src/features/home/user/workspace/ui/WorkingStoresList.tsx`:
- Line 28: The section in the WorkingStoresList component uses a hard fixed
width class "w-[358px]" which can cause overflow; update the section's class to
use responsive sizing (e.g., replace "w-[358px]" with "w-full max-w-[358px]") so
the container can shrink in tight layouts while keeping the intended maximum
width.
In `@src/pages/manager/worker-schedule/index.tsx`:
- Around line 63-66: Extract the hardcoded gradient avatar placeholder into a
reusable component or CSS utility so the color (`#ececec`) can be centralized:
create a PlaceholderAvatar React component (or a .placeholder-avatar utility)
that renders the div with the repeating-conic-gradient and accepts a prop or CSS
variable for the base color, then replace the inline div in the worker-schedule
page with <PlaceholderAvatar /> (or apply the .placeholder-avatar class) so the
pattern and color are reusable across the app.
In `@src/pages/user/applied-stores/index.tsx`:
- Around line 34-37: The cancel handler (handleCancel) can trigger multiple
requests if invoked rapidly; add a guard using the cancellation state (e.g.,
isCancelling or cancelApplication.isLoading) to early-return when a cancellation
is already in progress, and ensure the modal/button is disabled while cancelling
to prevent double-invocation; update the modal's cancel button to use that
disabled state and keep closeDetail called only from the mutation onSuccess so
duplicate calls won't race with selectedStore becoming stale.
In `@src/pages/user/workspace-detail/index.tsx`:
- Around line 24-30: The destructured variable "mode" from
useWorkspaceScheduleViewModel(id) is unused; remove "mode" from the
destructuring to eliminate the unused variable warning, or if mode switching is
intended, wire the returned "mode" into the component's state/JSX logic (e.g.,
pass it to rendering conditionals or handlers). Locate the call
useWorkspaceScheduleViewModel in the component and either delete "mode" from the
destructured list or use "mode" where appropriate (e.g., in rendering or effect
logic) to reflect the view model's mode.
- Around line 91-92: The onOptions prop is currently passed an empty no-op which
signals incomplete behavior; update the component instance that sets onOptions
to either wire it to a real handler (e.g., implement and pass a function like
handleOptions in this module that opens the options menu, navigates, or triggers
the intended action) or at minimum replace the empty arrow with a clear TODO
comment (e.g., // TODO: implement options handler) so the placeholder is
explicit; locate the prop usage named onOptions in this file and connect it to
the appropriate handler function or add the TODO inline.
In `@src/shared/lib/queryKeys.ts`:
- Around line 1-7: The shared util queryKeys currently imports
SelfScheduleQueryParams from a feature API which inverts dependencies; extract
SelfScheduleQueryParams into a lower-level shared types module (a small
types-only file) and re-export it so both the feature API (where the type
originated) and this shared/lib/queryKeys import the type from that new module
instead of from the feature API; update the import in the queryKeys file to
reference the new types module and update the feature API to import the type
from the same new module.
In `@src/shared/ui/manager/OngoingPostingCard.tsx`:
- Around line 68-74: In OngoingPostingCard.tsx replace the hardcoded hex values
in the span className (the conditional branch that uses isUrgent and renders
posting.dDay) with Tailwind tokens (e.g., use bg-urgent text-urgent for the
urgent branch and bg-urgent-light text-urgent for the non-urgent branch),
updating the template literal around isUrgent accordingly; if those tokens don’t
exist yet, add semantic color tokens (bg-urgent, bg-urgent-light, text-urgent)
under theme.extend.colors in tailwind.config.js and then run the Tailwind build
so the new classes are available.
In `@src/shared/ui/manager/SubstituteApprovalCard.tsx`:
- Around line 28-33: The statusConfig object in SubstituteApprovalCard (and
related UI pieces: the avatar fallback and the role pill) uses hardcoded hex
colors—replace those hex literals (e.g., text-[`#3A9982`], border-[`#3A9982`],
bg-[`#EFEFEF`], text-[`#2CE283`], bg-[`#EAFDF3`], text-[`#E28D2C`], bg-[`#FDF8EA`]) with
the registered Tailwind tokens so the UI remains themeable: use text-sub and
border-sub for the green sub color and bg-bg-dark for the gray background;
update the statusConfig entries, the avatar fallback rendering, and the role
pill className in SubstituteApprovalCard, and apply the same token replacements
in src/pages/manager/home/index.tsx and any files under
src/shared/ui/manager/**/*.tsx that still contain hardcoded hexes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/shared/ui/common/Docbar.tsx (1)
118-124:⚠️ Potential issue | 🔴 CriticalMultiple Docbar tabs route to non-existent pages.
The
pathByTabmapping references routes that don't exist in your router:/message,/repute, and/myhave no corresponding route definitions insrc/app/App.tsx. Additionally, thesearchtab is hardcoded to/user/job-lookup-mapregardless of user scope—there is no/manager/job-lookup-mapequivalent. When users click these tabs, they will navigate to undefined routes, breaking the experience.Either add the missing route definitions (
/message,/repute,/my, and optionally/manager/job-lookup-mapif managers need a separate search page), or remove these tabs from the UI until the routes are available.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/common/Docbar.tsx` around lines 118 - 124, pathByTab currently maps TabKey entries (home, search, message, repute, my) to routes that don't exist in the router, causing broken navigation; update the mapping in Docbar.tsx so each TabKey points to an existing route or is conditionally omitted for scopes that lack a page. Specifically, either add the missing routes in the app router (for example handlers for "/message", "/repute", "/my" and optionally "/manager/job-lookup-map") or change the pathByTab object and any code that renders tabs (referenced by pathByTab and TabKey and the scope variable) to: 1) point search to a valid route based on scope, and 2) remove or hide entries for message/repute/my when no route exists so clicks cannot navigate to undefined paths.src/pages/manager/home/index.tsx (1)
182-190:⚠️ Potential issue | 🟡 MinorWire the handlers or omit them to avoid misleading interactive states.
The
onOptions,onPostingClick, andonRequestClickcallbacks are explicitly empty functions, but the child components render interactive buttons with hover effects. This creates poor UX where users see clickable elements that do nothing. Either implement the handlers with actual functionality, or omit passing them entirely and let the child components render non-interactive states when handlers are not provided.Applies to lines 189, 210, and 225.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/manager/home/index.tsx` around lines 182 - 190, The components are being passed empty callbacks which produce misleading interactive UI; update the mapping that renders StoreWorkerListItem, StorePostingListItem, and StoreRequestListItem to either supply real handlers or remove the props so the child components render non-interactive states — specifically, stop passing onOptions from the storeWorkers.map loop to StoreWorkerListItem (or implement a real onOptions handler), stop passing onPostingClick to the postings list render, and stop passing onRequestClick to the requests list render; locate the render calls for StoreWorkerListItem, StorePostingListItem, and StoreRequestListItem and either implement the appropriate handler functions (e.g., openOptionsMenu, handlePostingClick, handleRequestClick) and pass them down, or omit those props so the children can render as non-interactive.
♻️ Duplicate comments (5)
src/pages/signup/components/EmailVerification.tsx (2)
92-99:⚠️ Potential issue | 🔴 CriticalSame invalid-CSS bug —
color: 'main' | 'error'won't apply.Inline
style.colorneeds a real CSS color;'main'/'error'are Tailwind keys and will be ignored. Usecolors.main.DEFAULT/colors.error, or switch toclassName={verified ? 'text-main' : 'text-error'}.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/signup/components/EmailVerification.tsx` around lines 92 - 99, The inline style in the EmailVerification component uses invalid tokens ('main'/'error') for style.color which won't work; update the JSX that renders {message} to apply a valid Tailwind color class instead of style (e.g., replace style={{ color: verified ? 'main' : 'error' }} with a conditional className like verified ? 'text-main' : 'text-error') or supply actual color values from your colors export (e.g., colors.main.DEFAULT / colors.error) so the <p> uses a real CSS color; locate the JSX fragment that references message and verified in EmailVerification.tsx to make the change.
43-49:⚠️ Potential issue | 🔴 CriticalSame invalid-CSS bug — borderColor uses non-CSS token name.
'1px solid main'/'1px solid error'are passed directly into the inlineborderstyle byAuthInputand are not valid CSS, so verified/error border states won't render. Same fix asPhoneVerification.tsx: substitute the token hex (colors.main.DEFAULT,colors.error) or refactorAuthInputto accept a semantic state prop.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/signup/components/EmailVerification.tsx` around lines 43 - 49, The borderColor prop in EmailVerification.tsx is set to non-CSS strings ('1px solid main' / '1px solid error') which won't render; update the value passed into AuthInput to use actual CSS values (e.g., use the token hex values like colors.main.DEFAULT and colors.error combined with the width/style: "1px solid <hex>") or change AuthInput to accept a semantic state prop (e.g., verified/error) and have AuthInput map that to a proper CSS border; mirror the fix used in PhoneVerification.tsx so verified and error states render correctly.src/pages/signup/components/Step2AccountInfo.tsx (1)
112-135:⚠️ Potential issue | 🔴 CriticalSame invalid-CSS bug as PhoneVerification.
'1px solid main'/'1px solid error'on Line 114 & 116, andcolor: 'main' | 'error'on Line 131 are not valid CSS —main/errorare Tailwind config keys, not CSS keywords. The declarations are dropped by the browser, so the nickname validation no longer shows the intended green/red feedback. Use the resolved hex from@/shared/lib/tokensor Tailwindtext-main/text-error/border-main/border-errorclasses.🐛 Proposed fix
+import { colors } from '@/shared/lib/tokens' @@ borderColor={ nicknameChecked - ? '1px solid main' + ? `1px solid ${colors.main.DEFAULT}` : nicknameCheckMessage - ? '1px solid error' + ? `1px solid ${colors.error}` : undefined } @@ - style={{ color: nicknameChecked ? 'main' : 'error' }} + style={{ color: nicknameChecked ? colors.main.DEFAULT : colors.error }}Based on learnings: avoid hardcoding colors; use tokens registered in
tailwind.config.js/src/shared/lib/tokens.ts.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/signup/components/Step2AccountInfo.tsx` around lines 112 - 135, The nickname validation UI uses invalid inline CSS values ('1px solid main' / '1px solid error' and color: 'main'|'error') which are dropped by the browser; update the JSX in Step2AccountInfo (around the Input that uses nicknameChecked and nicknameCheckMessage and the <VerifyActionButton>) to use either the color tokens imported from '@/shared/lib/tokens' (apply the resolved hex values to borderColor and color) or swap the inline styles for Tailwind utility classes like border-main / border-error and text-main / text-error conditionally based on nicknameChecked and nicknameCheckMessage; ensure the className or style changes target the same elements that currently reference nicknameChecked and nicknameCheckMessage so the green/red feedback appears correctly.src/features/home/user/workspace/api/workspaceSchedule.ts (1)
124-130:⚠️ Potential issue | 🟠 MajorKeep shifts that are currently in progress.
Line 125 drops any shift whose start time is before
now, even if the shift has not ended yet. Filter byendDateTimeso only fully elapsed shifts are excluded.🐛 Proposed fix
const sorted = response.data - .filter(shift => new Date(shift.startDateTime).getTime() >= now) + .filter(shift => new Date(shift.endDateTime).getTime() >= now) .sort( (a, b) => new Date(a.startDateTime).getTime() -🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/home/user/workspace/api/workspaceSchedule.ts` around lines 124 - 130, The current filter used when building the sorted array drops any shift whose startDateTime is before now, which incorrectly excludes shifts that are currently in progress; update the filter on response.data (the code that produces the sorted constant) to check shift.endDateTime (e.g., new Date(shift.endDateTime).getTime() >= now) so only shifts that have fully ended are excluded, then keep the existing sort by startDateTime to preserve ordering.src/pages/manager/home/index.tsx (1)
109-130:⚠️ Potential issue | 🟠 MajorWire or hide the workspace edit/add controls.
The modal still exposes user-visible controls that do nothing:
onEditWorkspace={() => {}}and the “업장 추가” button has noonClick. If these flows are not ready, hide the controls instead of shipping dead actions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/manager/home/index.tsx` around lines 109 - 130, The Workspace edit/add UI currently renders dead controls: the WorkspaceChangeList prop onEditWorkspace is an empty noop and the add-button (using managerWorkspaceModalPlusIcon) has no onClick; hide or remove these until implemented by conditionally rendering them (e.g., only pass onEditWorkspace or render the add button when the edit/add feature flag or handler exists). Locate the WorkspaceChangeList usage and remove or omit the onEditWorkspace prop (do not pass an empty ()=>{}) and wrap the button JSX in a conditional (or add a CSS hidden/aria-hidden state) so the add-button is not visible unless a real onClick handler or feature flag is present.
🧹 Nitpick comments (2)
src/shared/ui/common/Docbar.tsx (1)
112-112: Minor: select onlyscopefrom the store to avoid unnecessary re-renders.
useAuthStore()without a selector subscribes the component to every auth state change. Prefer a narrow selector.♻️ Proposed change
- const { scope } = useAuthStore() + const scope = useAuthStore(state => state.scope)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/common/Docbar.tsx` at line 112, The component currently calls useAuthStore() without a selector which subscribes Docbar to all auth changes; change the call to select only the scope (e.g., useAuthStore(state => state.scope)) and update usages accordingly so only scope is read from the store, reducing unnecessary re-renders in the Docbar component.src/pages/manager/home/index.tsx (1)
53-53: Replace hardcoded gradient colors with theme tokens.This reintroduces arbitrary color literals in TSX. If
#232323maps to the existing text palette, prefer tokenized classes such asfrom-text-100/0 to-text-100.♻️ Proposed fix
- <div className="pointer-events-none absolute inset-0 bg-gradient-to-b from-[rgba(35,35,35,0)] to-[`#232323`]" /> + <div className="pointer-events-none absolute inset-0 bg-gradient-to-b from-text-100/0 to-text-100" />Based on learnings, in the alter-client repository, avoid hardcoding colors in TSX files and use Tailwind tokens already registered in
tailwind.config.js.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/manager/home/index.tsx` at line 53, The gradient DIV currently uses a hardcoded color literal in its className ("bg-gradient-to-b from-[rgba(35,35,35,0)] to-[`#232323`]"); replace those literal values with the Tailwind theme tokens (e.g., use tokenized classes such as "from-text-100/0 to-text-100" or the appropriate text-* tokens defined in tailwind.config.js) so the DIV's className becomes token-based; update the className on the same DIV element in src/pages/manager/home/index.tsx and ensure the chosen tokens map to the same visual values in your tailwind config.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/features/home/manager/hooks/useManagedWorkspacesQuery.ts`:
- Around line 18-28: In useManagedWorkspacesQuery's useEffect, guard against an
empty workspaces array before calling workspaces.reduce by checking
workspaces.length > 0 (and handle the empty case accordingly), rename
hasVaildActiveWorkspace to hasValidActiveWorkspace, and fix the .some() callback
parameter shadowing by using a singular name (e.g., workspace => workspace.id
=== activeWorkspaceId); if no default exists, avoid calling setActiveWorkspaceId
or set it to null/undefined as appropriate to prevent errors in
setActiveWorkspaceId.
In `@src/features/home/user/schedule/api/schedule.ts`:
- Around line 16-26: getSelfSchedule currently fetches whole-month data when
fromYear/fromMonth/toYear/toMonth cover a range, but if fromDay/toDay are
present it returns the unfiltered month responses (schedules, eventCount,
totalWorkHours) instead of the requested week subset; update getSelfSchedule to
post-filter the monthly response to the requested day-range: use the incoming
SelfScheduleQueryParams.fromDay/fromMonth/fromYear and toDay/toMonth/toYear to
slice each month's schedules and recompute eventCount and totalWorkHours from
those filtered schedules before returning. Locate getSelfSchedule and the code
paths that assign schedules/eventCount/totalWorkHours (also check the similar
block around lines 86-115) and replace the direct return of month results with a
filtered aggregation over schedules that fall within the inclusive date range.
In `@src/features/home/user/workspace/api/workspaceSchedule.ts`:
- Around line 42-60: When handling the range branch where params?.fromYear is
defined and months differ, you must apply params.fromDay and params.toDay bounds
to the month-level results before merging to avoid returning whole months; after
fetching fromData and toData via fetchWorkspaceScheduleByMonth(workspaceId,
params.fromYear, params.fromMonth) and
fetchWorkspaceScheduleByMonth(workspaceId, params.toYear, params.toMonth),
filter fromData.data to only include entries with day >= params.fromDay and
filter toData.data to only include entries with day <= params.toDay (use the
same date field used by schedule entries), then return a combined object like {
...fromData, data: [...filteredFrom, ...filteredTo] } (ensure you preserve other
metadata from fromData/toData as appropriate).
In `@src/pages/manager/home/index.tsx`:
- Around line 142-144: The TodayWorkerList component is rendering fixture data
because todayWorkers is sourced from the TODAY_WORKERS constant; remove or guard
this render on real data readiness: in the manager home page replace the
unconditional <TodayWorkerList workers={todayWorkers} /> usage with a
conditional that only renders when the view model yields real data (e.g., a
non-empty/loaded flag from useManagerHomeViewModel) or show an empty/loading
state instead; locate TodayWorkerList usage in src/pages/manager/home/index.tsx
and the todayWorkers/TODAY_WORKERS source in useManagerHomeViewModel.ts to
implement the guard or swap to the real query before releasing.
- Around line 55-67: The banner renders workspaceDetail?.businessName twice;
remove the duplicate paragraph element that displays
workspaceDetail?.businessName (the second <p
className="typography-body01-regular leading-[1.4]">) so only the headline
(typography-headline01) shows the store name next to WorkCategoryBadge; keep the
address paragraph and adjust spacing if needed.
In `@src/pages/signup/components/PhoneVerification.tsx`:
- Around line 89-94: The inline style on the <p> in PhoneVerification.tsx is
setting style={{ color: verified ? 'main' : 'error' }} which are not valid CSS
colors; change this to either (a) resolve the design tokens to real color values
(e.g., style={{ color: tokens.colors.main }} / tokens.colors.error or hex
strings) or (b) use Tailwind classes conditionally via className (e.g.,
className={`${verified ? 'text-green-600' : 'text-red-600'} ...`}) so the
message color actually renders; update the paragraph that references verified
and message accordingly.
- Around line 39-45: The inline border values in PhoneVerification.tsx are
invalid because they pass Tailwind token names (e.g., '1px solid main' / '1px
solid error') into the AuthInput borderColor prop, which AuthInput applies
directly as a CSS border; replace those token names with actual CSS color values
from the shared tokens (import values from tokens.ts) and build a valid border
string (e.g., `1px solid ${tokens.primary}` or `1px solid ${tokens.error}`) when
setting borderColor, or alternatively change AuthInput to accept a token name
and resolve it internally.
---
Outside diff comments:
In `@src/pages/manager/home/index.tsx`:
- Around line 182-190: The components are being passed empty callbacks which
produce misleading interactive UI; update the mapping that renders
StoreWorkerListItem, StorePostingListItem, and StoreRequestListItem to either
supply real handlers or remove the props so the child components render
non-interactive states — specifically, stop passing onOptions from the
storeWorkers.map loop to StoreWorkerListItem (or implement a real onOptions
handler), stop passing onPostingClick to the postings list render, and stop
passing onRequestClick to the requests list render; locate the render calls for
StoreWorkerListItem, StorePostingListItem, and StoreRequestListItem and either
implement the appropriate handler functions (e.g., openOptionsMenu,
handlePostingClick, handleRequestClick) and pass them down, or omit those props
so the children can render as non-interactive.
In `@src/shared/ui/common/Docbar.tsx`:
- Around line 118-124: pathByTab currently maps TabKey entries (home, search,
message, repute, my) to routes that don't exist in the router, causing broken
navigation; update the mapping in Docbar.tsx so each TabKey points to an
existing route or is conditionally omitted for scopes that lack a page.
Specifically, either add the missing routes in the app router (for example
handlers for "/message", "/repute", "/my" and optionally
"/manager/job-lookup-map") or change the pathByTab object and any code that
renders tabs (referenced by pathByTab and TabKey and the scope variable) to: 1)
point search to a valid route based on scope, and 2) remove or hide entries for
message/repute/my when no route exists so clicks cannot navigate to undefined
paths.
---
Duplicate comments:
In `@src/features/home/user/workspace/api/workspaceSchedule.ts`:
- Around line 124-130: The current filter used when building the sorted array
drops any shift whose startDateTime is before now, which incorrectly excludes
shifts that are currently in progress; update the filter on response.data (the
code that produces the sorted constant) to check shift.endDateTime (e.g., new
Date(shift.endDateTime).getTime() >= now) so only shifts that have fully ended
are excluded, then keep the existing sort by startDateTime to preserve ordering.
In `@src/pages/manager/home/index.tsx`:
- Around line 109-130: The Workspace edit/add UI currently renders dead
controls: the WorkspaceChangeList prop onEditWorkspace is an empty noop and the
add-button (using managerWorkspaceModalPlusIcon) has no onClick; hide or remove
these until implemented by conditionally rendering them (e.g., only pass
onEditWorkspace or render the add button when the edit/add feature flag or
handler exists). Locate the WorkspaceChangeList usage and remove or omit the
onEditWorkspace prop (do not pass an empty ()=>{}) and wrap the button JSX in a
conditional (or add a CSS hidden/aria-hidden state) so the add-button is not
visible unless a real onClick handler or feature flag is present.
In `@src/pages/signup/components/EmailVerification.tsx`:
- Around line 92-99: The inline style in the EmailVerification component uses
invalid tokens ('main'/'error') for style.color which won't work; update the JSX
that renders {message} to apply a valid Tailwind color class instead of style
(e.g., replace style={{ color: verified ? 'main' : 'error' }} with a conditional
className like verified ? 'text-main' : 'text-error') or supply actual color
values from your colors export (e.g., colors.main.DEFAULT / colors.error) so the
<p> uses a real CSS color; locate the JSX fragment that references message and
verified in EmailVerification.tsx to make the change.
- Around line 43-49: The borderColor prop in EmailVerification.tsx is set to
non-CSS strings ('1px solid main' / '1px solid error') which won't render;
update the value passed into AuthInput to use actual CSS values (e.g., use the
token hex values like colors.main.DEFAULT and colors.error combined with the
width/style: "1px solid <hex>") or change AuthInput to accept a semantic state
prop (e.g., verified/error) and have AuthInput map that to a proper CSS border;
mirror the fix used in PhoneVerification.tsx so verified and error states render
correctly.
In `@src/pages/signup/components/Step2AccountInfo.tsx`:
- Around line 112-135: The nickname validation UI uses invalid inline CSS values
('1px solid main' / '1px solid error' and color: 'main'|'error') which are
dropped by the browser; update the JSX in Step2AccountInfo (around the Input
that uses nicknameChecked and nicknameCheckMessage and the <VerifyActionButton>)
to use either the color tokens imported from '@/shared/lib/tokens' (apply the
resolved hex values to borderColor and color) or swap the inline styles for
Tailwind utility classes like border-main / border-error and text-main /
text-error conditionally based on nicknameChecked and nicknameCheckMessage;
ensure the className or style changes target the same elements that currently
reference nicknameChecked and nicknameCheckMessage so the green/red feedback
appears correctly.
---
Nitpick comments:
In `@src/pages/manager/home/index.tsx`:
- Line 53: The gradient DIV currently uses a hardcoded color literal in its
className ("bg-gradient-to-b from-[rgba(35,35,35,0)] to-[`#232323`]"); replace
those literal values with the Tailwind theme tokens (e.g., use tokenized classes
such as "from-text-100/0 to-text-100" or the appropriate text-* tokens defined
in tailwind.config.js) so the DIV's className becomes token-based; update the
className on the same DIV element in src/pages/manager/home/index.tsx and ensure
the chosen tokens map to the same visual values in your tailwind config.
In `@src/shared/ui/common/Docbar.tsx`:
- Line 112: The component currently calls useAuthStore() without a selector
which subscribes Docbar to all auth changes; change the call to select only the
scope (e.g., useAuthStore(state => state.scope)) and update usages accordingly
so only scope is read from the store, reducing unnecessary re-renders in the
Docbar component.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4b55598d-fb0a-4717-a402-0486e5cd5ee1
📒 Files selected for processing (30)
src/features/home/common/schedule/ui/MonthlyCalendar.tsxsrc/features/home/common/schedule/ui/MonthlyDateCell.tsxsrc/features/home/manager/hooks/useManagedWorkspacesQuery.tssrc/features/home/manager/hooks/useWorkspaceDetailQuery.tssrc/features/home/manager/types/posting.tssrc/features/home/manager/types/storeWorkerRole.tssrc/features/home/manager/types/worker.tssrc/features/home/manager/types/workspace.tssrc/features/home/manager/ui/StoreWorkerListItem.tsxsrc/features/home/manager/ui/WorkspaceChangeCard.tsxsrc/features/home/manager/ui/WorkspaceChangeList.tsxsrc/features/home/user/applied-stores/hooks/useAppliedStoresViewModel.tssrc/features/home/user/applied-stores/types/application.tssrc/features/home/user/schedule/api/schedule.tssrc/features/home/user/schedule/lib/date.test.tssrc/features/home/user/schedule/lib/date.tssrc/features/home/user/workspace/api/workspaceSchedule.tssrc/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.tssrc/features/home/user/workspace/hooks/useWorkspaceWorkersViewModel.tssrc/features/home/user/workspace/types/workspaceSchedule.tssrc/pages/login/index.tsxsrc/pages/manager/home/index.tsxsrc/pages/manager/worker-schedule/index.tsxsrc/pages/signup/components/EmailVerification.tsxsrc/pages/signup/components/PhoneVerification.tsxsrc/pages/signup/components/SignupTerms.tsxsrc/pages/signup/components/Step2AccountInfo.tsxsrc/pages/user/workspace-members/hooks/useWorkspaceMembers.tssrc/shared/lib/queryKeys.tssrc/shared/ui/common/Docbar.tsx
✅ Files skipped from review due to trivial changes (8)
- src/pages/signup/components/SignupTerms.tsx
- src/features/home/manager/types/storeWorkerRole.ts
- src/features/home/manager/types/posting.ts
- src/features/home/user/workspace/hooks/useWorkspaceManagersViewModel.ts
- src/features/home/manager/types/workspace.ts
- src/features/home/user/workspace/types/workspaceSchedule.ts
- src/features/home/user/applied-stores/hooks/useAppliedStoresViewModel.ts
- src/shared/lib/queryKeys.ts
🚧 Files skipped from review as they are similar to previous changes (11)
- src/features/home/common/schedule/ui/MonthlyDateCell.tsx
- src/pages/login/index.tsx
- src/features/home/manager/hooks/useWorkspaceDetailQuery.ts
- src/features/home/user/schedule/lib/date.test.ts
- src/features/home/manager/ui/WorkspaceChangeCard.tsx
- src/features/home/user/workspace/hooks/useWorkspaceWorkersViewModel.ts
- src/features/home/manager/types/worker.ts
- src/features/home/common/schedule/ui/MonthlyCalendar.tsx
- src/pages/manager/worker-schedule/index.tsx
- src/pages/user/workspace-members/hooks/useWorkspaceMembers.ts
- src/features/home/user/applied-stores/types/application.ts
| borderColor={ | ||
| verified | ||
| ? '1px solid #2DE283' | ||
| ? '1px solid main' | ||
| : message && !smsSent | ||
| ? '1px solid #DC0000' | ||
| ? '1px solid error' | ||
| : undefined | ||
| } |
There was a problem hiding this comment.
Invalid CSS: Tailwind token names used as inline style values.
AuthInput applies borderColor directly as a CSS border value (see src/shared/ui/common/AuthInput.tsx:20). '1px solid main' and '1px solid error' are not valid CSS — main/error are Tailwind config keys, not CSS color keywords — so the browser drops the declaration and the success/failure border styling is lost entirely. Use the token hex values from src/shared/lib/tokens.ts (or change AuthInput to accept a token name and map it internally).
🐛 Proposed fix
+import { colors } from '@/shared/lib/tokens'
@@
borderColor={
verified
- ? '1px solid main'
+ ? `1px solid ${colors.main.DEFAULT}`
: message && !smsSent
- ? '1px solid error'
+ ? `1px solid ${colors.error}`
: undefined
}Based on learnings: avoid hardcoding colors; prefer the tokens defined in src/shared/lib/tokens.ts / tailwind.config.js.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/signup/components/PhoneVerification.tsx` around lines 39 - 45, The
inline border values in PhoneVerification.tsx are invalid because they pass
Tailwind token names (e.g., '1px solid main' / '1px solid error') into the
AuthInput borderColor prop, which AuthInput applies directly as a CSS border;
replace those token names with actual CSS color values from the shared tokens
(import values from tokens.ts) and build a valid border string (e.g., `1px solid
${tokens.primary}` or `1px solid ${tokens.error}`) when setting borderColor, or
alternatively change AuthInput to accept a token name and resolve it internally.
| <p | ||
| className="font-pretendard font-regular text-[12px] leading-[18px] text-left w-full sm:text-[11px] xs:text-[10px]" | ||
| style={{ color: verified ? '#2DE283' : '#DC0000' }} | ||
| style={{ color: verified ? 'main' : 'error' }} | ||
| > | ||
| {message} | ||
| </p> |
There was a problem hiding this comment.
Invalid CSS: color: 'main' | 'error' will not render.
Inline style.color receives the raw strings 'main' / 'error', which are not valid CSS color values, so the message color falls back to the inherited default (success/failure are visually indistinguishable). Resolve the token to its hex, or switch to a Tailwind class via className.
🐛 Proposed fix
- style={{ color: verified ? 'main' : 'error' }}
+ className="... " // keep existing classes, plus:
+ // use Tailwind: className={`${base} ${verified ? 'text-main' : 'text-error'}`}Or with tokens:
- style={{ color: verified ? 'main' : 'error' }}
+ style={{ color: verified ? colors.main.DEFAULT : colors.error }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/signup/components/PhoneVerification.tsx` around lines 89 - 94, The
inline style on the <p> in PhoneVerification.tsx is setting style={{ color:
verified ? 'main' : 'error' }} which are not valid CSS colors; change this to
either (a) resolve the design tokens to real color values (e.g., style={{ color:
tokens.colors.main }} / tokens.colors.error or hex strings) or (b) use Tailwind
classes conditionally via className (e.g., className={`${verified ?
'text-green-600' : 'text-red-600'} ...`}) so the message color actually renders;
update the paragraph that references verified and message accordingly.





ID
변경 내용
features/home/common으로 이동하여 알바생·사장님 공용으로 리팩토링구현 사항
알바생 (User)
사장님 (Manager)
activeWorkspaceId로 전역 관리)공통 리팩토링
MonthlyCalendar,MonthlyDateCell,MonthlyDateGauge등 캘린더 UI 컴포넌트를features/home/common/schedule로 이동CalendarViewData,CalendarEvent등 공유 타입 및 날짜 유틸(toDateKey,toTimeLabel,getDurationHours) common으로 통합shared/lib/queryKeys.ts에서 중앙 관리참고 사항 (필요 시)
activeWorkspaceId는 Zustand persist로 관리되며, queryKey에 포함되어 업장 전환 시 모든 관련 쿼리가 자동으로 refetch됩니다Summary by CodeRabbit
New Features
Refactor