Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthrough새 할당, 과정 API 함수 추가 및 React Query 패턴을 Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes Possibly related PRs
Suggested labels
Suggested reviewers
💡 추가 검토 사항긍정적인 부분:
개선 제안:
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/select-assignment/ui/AssignmentListContainer.tsx (1)
4-10:⚠️ Potential issue | 🟠 Major제네릭 타입과
onSelect콜백의 타입 불일치 해결 필요
T는AssignmentSelectCourse['assignments'][number](즉,Pick<Assignment, 'id' | 'title'>)으로 정의되지만,onSelect콜백과handleSelect는 완전한Assignment타입을 기대합니다. 구조적 호환성으로 인해 TypeScript는 컴파일하지만, 의도하지 않은 타입 불일치입니다.제네릭을 일관되게 사용하여 타입 안전성을 강화하세요.
♻️ 제네릭 제약 추가 제안
-type T = AssignmentSelectCourse['assignments'][number]; - interface AssignmentListContainerProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; title: string; - onSelect: (item: Assignment) => void; + onSelect: (item: T) => void; } const AssignmentListContainer = ({ onSelect, items, renderItem, title, -}: AssignmentListContainerProps<T>) => { - const handleSelect = (item: Assignment, event: React.MouseEvent) => { +}: AssignmentListContainerProps<T extends Assignment>) => { + const handleSelect = (item: T, event: React.MouseEvent) => { event.stopPropagation(); onSelect(item); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/select-assignment/ui/AssignmentListContainer.tsx` around lines 4 - 10, The props type is inconsistent: T is defined as AssignmentSelectCourse['assignments'][number] (a partial Pick) while onSelect and handleSelect expect a full Assignment; change AssignmentListContainerProps to use a generic T for the item type consistently and update the callback/signature to match that generic (for example declare interface AssignmentListContainerProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; title: string; onSelect: (item: T) => void } and ensure the component’s handleSelect(item: T) and any usages pass the same T), or alternatively constrain T with T extends Assignment if you need full Assignment fields—apply the same T to renderItem, onSelect, and handleSelect to ensure type safety.
🧹 Nitpick comments (3)
src/pages/select-assignment/ui/AssignmentListContainer.tsx (1)
19-21:handleSelect의 item 타입도 제네릭으로 통일 권장현재
handleSelect는item: Assignment로 고정되어 있어 제네릭T와 일치하지 않습니다. 위의 제네릭 제약 수정과 함께 이 부분도T로 변경하면 타입 일관성이 향상됩니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/select-assignment/ui/AssignmentListContainer.tsx` around lines 19 - 21, handleSelect 함수의 인자 item이 구체적 타입 Assignment로 고정되어 있어 컴포넌트의 제네릭 T와 불일치하므로 handleSelect 시그니처를 Assignment 대신 제네릭 T로 변경하고 내부 호출(onSelect)에 전달되는 타입도 일치시키세요; 관련 식별자는 handleSelect, onSelect, 그리고 기존 Assignment 타입 제약이며 제네릭 T가 선언된 상위 컴포넌트 타입과 함께 업데이트하면 타입 일관성이 유지됩니다.src/entities/unit/api/unitMutations.ts (1)
8-22: 파라미터 네이밍 일관성 부족
createUnit은unitForm을 사용하고,updateUnit은unit을 사용합니다. 동일한TUnitFormSchema타입을 받으므로 네이밍을 통일하는 것이 좋습니다.♻️ 네이밍 통일 제안
// 단원 수정 뮤테이션 옵션 updateUnit: { mutationKey: ['updateUnit'], - mutationFn: ({unitId, unit}: {unitId: number; unit: TUnitFormSchema}) => - updateUnit(unitId, unit), + mutationFn: ({unitId, unitForm}: {unitId: number; unitForm: TUnitFormSchema}) => + updateUnit(unitId, unitForm), },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/entities/unit/api/unitMutations.ts` around lines 8 - 22, The parameter naming is inconsistent between the createUnit and updateUnit mutationFns; updateUnit destructures and types the unit payload as "unit" while createUnit uses "unitForm". Update the updateUnit mutationFn to destructure ({unitId, unitForm}: {unitId: number; unitForm: TUnitFormSchema}) and call updateUnit(unitId, unitForm) so both mutations use the same "unitForm" name (referencing createUnit, updateUnit, and the mutationFn definitions).src/entities/unit/model/useUnitStore.ts (1)
31-32: 주석 의미가 현재 저장 구조와 다릅니다.Line 31 주석은 “ID 저장”인데, 실제 구현은
Assignment[]전체를 저장합니다. 유지보수 시 오해를 줄이도록 주석을 맞춰주세요.✏️ 제안 수정안
- // 선택된 과제 ID 저장 + // 선택된 과제 객체 목록 저장 setAssignments: (assignments) => set({assignments}),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/entities/unit/model/useUnitStore.ts` around lines 31 - 32, 주석과 구현이 불일치합니다: useUnitStore.ts의 setAssignments 함수는 "선택된 과제 ID 저장"이라고 주석돼 있지만 실제로는 Assignment[] 전체를 상태에 저장합니다; setAssignments 주석을 해당 동작을 정확히 반영하도록 수정하고(예: "선택된 과제 배열 저장" 또는 "선택된 Assignment들 저장"), 필요하면 파라미터 타입 설명(Assignment[])도 함께 업데이트하여 오해를 방지하세요.
🤖 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/entities/assignment/api/assignmentApi.ts`:
- Around line 45-46: Remove the development console.log in the
getAssignmentsByCourse API function (the line logging response.data) to avoid
leaking data and noisy logs in production; either delete that console.log
entirely or guard it behind a debug flag/config check (e.g., use a
process.env.DEBUG or isLocalDebug boolean) so logging only occurs in local/dev
runs, and keep the function return value (response.data) unchanged.
In `@src/pages/select-assignment/AssignmentSelectPage.tsx`:
- Around line 52-58: The navigate call currently passes state even when using
delta navigation (navigate(-1)), but React Router v7 ignores state for delta
moves; update the logic around the navigate(location.state?.backPath ?? -1, {
state: ... }) call in AssignmentSelectPage so that if location.state?.backPath
exists you call navigate(backPath, { state: { mode: location.state?.mode,
unitId: location.state?.unitId, currentIndex: location.state?.currentIndex } }),
otherwise call navigate(-1) (no state) to perform a history delta move; adjust
the branch around navigate to separate path navigation from delta navigation and
use the same state object only for path-based navigation.
In `@src/pages/unit-editor/ui/UnitForm.tsx`:
- Around line 155-159: The current conditional in UnitForm.tsx renders the
global `assignments` when `mode === 'editing'` and `unit.assignmentCount === 0`,
leaking temporary assignments into the edit UI; update the render logic so that
when `mode === 'editing'` you always use `unit.assignments` (even if empty) or
otherwise do not fall through to the global `assignments`. Concretely, change
the branching around `mode`, `unit`, `unit.assignmentCount`, and `assignments`
so `UnitAssignmentList assignmentList={unit.assignments}` is chosen whenever
`mode === 'editing' && unit` (or add an explicit `mode !== 'editing'` guard
before showing `assignments`) to prevent global `assignments` from being shown
in edit mode.
In `@src/pages/unit-editor/UnitEditorPage.tsx`:
- Around line 81-85: After deleting a unit you switch UI to creating mode but
forget to clear the editor store, causing residual form values to persist;
update the onSuccess handler to call resetStore() (the same store reset used
after create) before or immediately after setMode('creating'), keeping
invalidateUnitList(), setSelectedUnitId(null), setMode('creating'), and then
resetStore() so the create form is cleared and state stays consistent.
---
Outside diff comments:
In `@src/pages/select-assignment/ui/AssignmentListContainer.tsx`:
- Around line 4-10: The props type is inconsistent: T is defined as
AssignmentSelectCourse['assignments'][number] (a partial Pick) while onSelect
and handleSelect expect a full Assignment; change AssignmentListContainerProps
to use a generic T for the item type consistently and update the
callback/signature to match that generic (for example declare interface
AssignmentListContainerProps<T> { items: T[]; renderItem: (item: T) =>
React.ReactNode; title: string; onSelect: (item: T) => void } and ensure the
component’s handleSelect(item: T) and any usages pass the same T), or
alternatively constrain T with T extends Assignment if you need full Assignment
fields—apply the same T to renderItem, onSelect, and handleSelect to ensure type
safety.
---
Nitpick comments:
In `@src/entities/unit/api/unitMutations.ts`:
- Around line 8-22: The parameter naming is inconsistent between the createUnit
and updateUnit mutationFns; updateUnit destructures and types the unit payload
as "unit" while createUnit uses "unitForm". Update the updateUnit mutationFn to
destructure ({unitId, unitForm}: {unitId: number; unitForm: TUnitFormSchema})
and call updateUnit(unitId, unitForm) so both mutations use the same "unitForm"
name (referencing createUnit, updateUnit, and the mutationFn definitions).
In `@src/entities/unit/model/useUnitStore.ts`:
- Around line 31-32: 주석과 구현이 불일치합니다: useUnitStore.ts의 setAssignments 함수는 "선택된 과제
ID 저장"이라고 주석돼 있지만 실제로는 Assignment[] 전체를 상태에 저장합니다; setAssignments 주석을 해당 동작을 정확히
반영하도록 수정하고(예: "선택된 과제 배열 저장" 또는 "선택된 Assignment들 저장"), 필요하면 파라미터 타입
설명(Assignment[])도 함께 업데이트하여 오해를 방지하세요.
In `@src/pages/select-assignment/ui/AssignmentListContainer.tsx`:
- Around line 19-21: handleSelect 함수의 인자 item이 구체적 타입 Assignment로 고정되어 있어 컴포넌트의
제네릭 T와 불일치하므로 handleSelect 시그니처를 Assignment 대신 제네릭 T로 변경하고 내부 호출(onSelect)에 전달되는
타입도 일치시키세요; 관련 식별자는 handleSelect, onSelect, 그리고 기존 Assignment 타입 제약이며 제네릭 T가 선언된
상위 컴포넌트 타입과 함께 업데이트하면 타입 일관성이 유지됩니다.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
src/entities/assignment/api/assignmentApi.tssrc/entities/assignment/api/assignmentQueries.tssrc/entities/assignment/api/assignmentQueryOptions.tssrc/entities/assignment/model/types.tssrc/entities/course/api/courseApi.tssrc/entities/course/api/courseMutations.tssrc/entities/course/api/courseQueries.tssrc/entities/course/api/courseQueryOptions.tssrc/entities/course/index.tssrc/entities/unit/api/unitApi.tssrc/entities/unit/api/unitMutations.tssrc/entities/unit/model/useUnitStore.tssrc/pages/dashboard/Dashboard.tsxsrc/pages/select-assignment/AssignmentSelectPage.tsxsrc/pages/select-assignment/ui/AssignmentListContainer.tsxsrc/pages/unit-editor/UnitEditorPage.tsxsrc/pages/unit-editor/ui/UnitForm.tsxsrc/shared/ui/Layout.tsx
💤 Files with no reviewable changes (3)
- src/entities/course/api/courseQueryOptions.ts
- src/entities/course/index.ts
- src/entities/assignment/api/assignmentQueryOptions.ts
| console.log('getAssignmentsByCourse API 응답:', response.data); // 응답 데이터 로깅 | ||
| return response.data; |
There was a problem hiding this comment.
API 응답 디버그 로그는 릴리스 전에 제거해 주세요.
Line 45의 console.log는 운영 환경에서 불필요한 데이터 노출과 콘솔 노이즈를 만듭니다. 필요하면 로컬 디버깅 플래그 기반으로 제한해 주세요.
🧼 제안 수정안
- console.log('getAssignmentsByCourse API 응답:', response.data); // 응답 데이터 로깅
return response.data;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.log('getAssignmentsByCourse API 응답:', response.data); // 응답 데이터 로깅 | |
| return response.data; | |
| return response.data; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/entities/assignment/api/assignmentApi.ts` around lines 45 - 46, Remove
the development console.log in the getAssignmentsByCourse API function (the line
logging response.data) to avoid leaking data and noisy logs in production;
either delete that console.log entirely or guard it behind a debug flag/config
check (e.g., use a process.env.DEBUG or isLocalDebug boolean) so logging only
occurs in local/dev runs, and keep the function return value (response.data)
unchanged.
| navigate(location.state?.backPath ?? -1, { | ||
| state: { | ||
| mode: location.state?.mode, | ||
| unitId: location.state?.unitId, | ||
| currentIndex: location.state?.currentIndex, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd /tmp && git ls-files | grep -i "AssignmentSelectPage" | head -5Repository: 2025-snowCode/snowCode-Client
Length of output: 141
🌐 Web query:
React Router v7 useNavigate delta navigation state parameter behavior
💡 Result:
In React Router v7, useNavigate() has two distinct call forms: navigate(to, options?) and navigate(delta) (history stack movement). When you use the delta form (e.g. navigate(-1)), you are effectively calling the underlying history “go” operation, which does not create a new location entry—so there’s nowhere to attach a new state payload. As a result, any “state parameter” you might expect to pass is not applied; you simply land on the existing entry and get whatever location.state was stored on that entry. [1], [2]
If you need to send new state, use path navigation instead: navigate("/path", { state }) (or the v7-supported navigate({ pathname, state })). [1]
Sources:
[1] React Router v7 useNavigate API reference (api.reactrouter.com)
[2] React Router Navigator interface (go(delta) vs push/replace(..., state)) (api.reactrouter.com)
Citations:
- 1: https://api.reactrouter.com/v7/functions/react-router.useNavigate
- 2: https://api.reactrouter.com/dev/interfaces/react_router.Navigator.html?utm_source=openai
🏁 Script executed:
fd "AssignmentSelectPage.tsx" --type fRepository: 2025-snowCode/snowCode-Client
Length of output: 125
🏁 Script executed:
cat -n src/pages/select-assignment/AssignmentSelectPage.tsx 2>/dev/null || find . -name "AssignmentSelectPage.tsx" -type f -exec cat -n {} \;Repository: 2025-snowCode/snowCode-Client
Length of output: 3720
Delta 이동 시 state 파라미터가 적용되지 않습니다.
52줄의 navigate(location.state?.backPath ?? -1, { state }) 호출은 backPath가 없으면 navigate(-1, { state })가 되는데, React Router v7에서 delta 이동(navigate(-1))은 브라우저의 history.go() 동작을 수행하므로 state 파라미터가 무시됩니다. 따라서 이전 페이지로 돌아갈 때 모드, unitId, currentIndex 정보가 손실됩니다.
해결 방법: path와 delta를 분리하여 처리하세요. backPath가 있으면 path 이동으로 state를 함께 전달하고, 없으면 delta 이동만 수행하세요.
🔧 수정 제안
const returnToPreviousPage = () => {
+ const backPath = location.state?.backPath;
+ const nextState = {
+ mode: location.state?.mode,
+ unitId: location.state?.unitId,
+ currentIndex: location.state?.currentIndex,
+ };
+
+ if (backPath) {
+ navigate(backPath, { state: nextState });
+ return;
+ }
+ navigate(-1);
- navigate(location.state?.backPath ?? -1, {
- state: {
- mode: location.state?.mode,
- unitId: location.state?.unitId,
- currentIndex: location.state?.currentIndex,
- },
- });
};참고: React Router v7 useNavigate API 문서
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/select-assignment/AssignmentSelectPage.tsx` around lines 52 - 58,
The navigate call currently passes state even when using delta navigation
(navigate(-1)), but React Router v7 ignores state for delta moves; update the
logic around the navigate(location.state?.backPath ?? -1, { state: ... }) call
in AssignmentSelectPage so that if location.state?.backPath exists you call
navigate(backPath, { state: { mode: location.state?.mode, unitId:
location.state?.unitId, currentIndex: location.state?.currentIndex } }),
otherwise call navigate(-1) (no state) to perform a history delta move; adjust
the branch around navigate to separate path navigation from delta navigation and
use the same state object only for path-based navigation.
| {mode === 'editing' && unit && unit.assignmentCount > 0 ? ( | ||
| <UnitAssignmentList assignmentList={unit.assignments} /> | ||
| ) : assignments.length > 0 ? ( | ||
| <UnitAssignmentList assignmentList={assignments} /> | ||
| ) : ( |
There was a problem hiding this comment.
편집 모드에서 다른 단원의 임시 과제가 노출될 수 있습니다.
Line 157-159 분기 때문에 editing인데 unit.assignmentCount === 0이면 전역 store의 assignments가 표시됩니다. 이전 생성 플로우 임시값이 섞여 보여 UX와 데이터 신뢰성을 깨뜨립니다.
✅ 제안 수정안
- {mode === 'editing' && unit && unit.assignmentCount > 0 ? (
- <UnitAssignmentList assignmentList={unit.assignments} />
- ) : assignments.length > 0 ? (
- <UnitAssignmentList assignmentList={assignments} />
- ) : (
- <EmptyState className='mt-4 mb-5'>
- 등록된 문제가 없습니다.
- </EmptyState>
- )}
+ {mode === 'editing' && unit ? (
+ unit.assignmentCount > 0 ? (
+ <UnitAssignmentList assignmentList={unit.assignments} />
+ ) : (
+ <EmptyState className='mt-4 mb-5'>
+ 등록된 문제가 없습니다.
+ </EmptyState>
+ )
+ ) : assignments.length > 0 ? (
+ <UnitAssignmentList assignmentList={assignments} />
+ ) : (
+ <EmptyState className='mt-4 mb-5'>
+ 등록된 문제가 없습니다.
+ </EmptyState>
+ )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/unit-editor/ui/UnitForm.tsx` around lines 155 - 159, The current
conditional in UnitForm.tsx renders the global `assignments` when `mode ===
'editing'` and `unit.assignmentCount === 0`, leaking temporary assignments into
the edit UI; update the render logic so that when `mode === 'editing'` you
always use `unit.assignments` (even if empty) or otherwise do not fall through
to the global `assignments`. Concretely, change the branching around `mode`,
`unit`, `unit.assignmentCount`, and `assignments` so `UnitAssignmentList
assignmentList={unit.assignments}` is chosen whenever `mode === 'editing' &&
unit` (or add an explicit `mode !== 'editing'` guard before showing
`assignments`) to prevent global `assignments` from being shown in edit mode.
| onSuccess: () => { | ||
| invalidateUnitList(); | ||
| setMode('idle'); // 삭제 후 대기 모드로 전환 | ||
| setSelectedUnitId(null); // 선택된 단원 초기화 | ||
| setMode('creating'); | ||
| alert('단원이 성공적으로 삭제되었습니다.'); |
There was a problem hiding this comment.
삭제 후 생성 모드 전환 시 store 초기화도 같이 필요합니다.
Line 84에서 생성 모드로 바꾸지만 resetStore()가 없어 이전 임시 입력값이 새 단원 폼에 남을 수 있습니다. create 성공 시와 동일하게 초기화해 상태 일관성을 맞춰주세요.
🧹 제안 수정안
onSuccess: () => {
invalidateUnitList();
setSelectedUnitId(null); // 선택된 단원 초기화
+ resetStore(); // 임시 단원 폼 상태 초기화
setMode('creating');
alert('단원이 성공적으로 삭제되었습니다.');
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onSuccess: () => { | |
| invalidateUnitList(); | |
| setMode('idle'); // 삭제 후 대기 모드로 전환 | |
| setSelectedUnitId(null); // 선택된 단원 초기화 | |
| setMode('creating'); | |
| alert('단원이 성공적으로 삭제되었습니다.'); | |
| onSuccess: () => { | |
| invalidateUnitList(); | |
| setSelectedUnitId(null); // 선택된 단원 초기화 | |
| resetStore(); // 임시 단원 폼 상태 초기화 | |
| setMode('creating'); | |
| alert('단원이 성공적으로 삭제되었습니다.'); | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/pages/unit-editor/UnitEditorPage.tsx` around lines 81 - 85, After
deleting a unit you switch UI to creating mode but forget to clear the editor
store, causing residual form values to persist; update the onSuccess handler to
call resetStore() (the same store reset used after create) before or immediately
after setMode('creating'), keeping invalidateUnitList(),
setSelectedUnitId(null), setMode('creating'), and then resetStore() so the
create form is cleared and state stays consistent.
⚙️ Related ISSUE Number
Related #52
📄 Work Description
API 연동
과제 선택 페이지
Assignment객체 기반으로 변경useUnitStore에 저장 후 이전 페이지로 복귀단원 폼 상태 유지
sessionStorage에 임시 저장 (useUnitStore)title,releaseDate,dueDate,assignments) 복원📷 Screenshot
💬 To Reviewers
TODO
🔗 Reference