Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
426d344
#15 feat: svg 아이콘 추가 및 변경
suminb99 Aug 18, 2025
e9bcab8
#15 feat: 단원 개설 페이지 라우트 추가
suminb99 Aug 18, 2025
8f072b9
#15 style: input-field 및 label 공통 스타일 정의
suminb99 Aug 18, 2025
2f157d6
#15 feat: 버튼 secondaryPurple variant 추가
suminb99 Aug 18, 2025
20da864
#15 feat: 단원 개설 페이지 컴포넌트 추가
suminb99 Aug 18, 2025
3db20b2
#15 feat: 단원 개설 페이지 기본 레이아웃 및 UI 구성 요소 구현
suminb99 Aug 18, 2025
585765b
#15 refactor: 버튼 컴포넌트에 color props 전달
suminb99 Aug 18, 2025
4b66206
#15 refactor: 과제 카드 색상 props로 배경색 설정
suminb99 Aug 18, 2025
72f148f
#15 feat: 전역 스타일에 box-sizing: border-box 추가
suminb99 Aug 18, 2025
71d7c72
#15 style: 레이아웃 높이 설정 및 overflow 시 scroll 적용
suminb99 Aug 18, 2025
f9a7765
#15 style: 버튼 컴포넌트 wrapper 패딩값 수정
suminb99 Aug 18, 2025
dc9afd8
#15 chore: dummy 과제 추가
suminb99 Sep 1, 2025
effcb19
Merge branch 'develop' into feat/15-unit-page
suminb99 Feb 8, 2026
c5be347
Merge branch 'refactor/17-assignment-select-update' into feat/15-unit…
suminb99 Feb 8, 2026
4c29d4c
Merge branch 'develop' into feat/15-unit-page
suminb99 Feb 8, 2026
8d93737
style: LabeledInput 흰생 배경 적용
suminb99 Feb 9, 2026
9364a80
refactor: Button.tsx classname explicitly 추가
suminb99 Feb 9, 2026
420c7b3
#15 fix: Assignment 인터페이스의 submittedStatus optional로 변경
suminb99 Feb 9, 2026
6ae32b4
#15 feat: 단원 조회-생성 페이지 더미 응답 데이터 및 타입 추가
suminb99 Feb 9, 2026
e0390b5
#15 feat: 단원 생성 라우트를 admin 하위로 이동 및 CreateUnitPage 적용
suminb99 Feb 9, 2026
dd0b2d2
#15 feat: binIcon public -> src/assets 하위로 이동
suminb99 Feb 9, 2026
3bd6f5b
#15 feat: CreatUnitPage 추가
suminb99 Feb 9, 2026
d3d758c
#15 feat: 단원 편집 섹션 (UnitFormEditor) 추가
suminb99 Feb 9, 2026
e25f7f7
#15 feat: 단원 목록 (UnitList) 추가
suminb99 Feb 9, 2026
b6cc590
#15 chorer: 기존 단원 관련 컴포넌트 및 더미 데이터 제거
suminb99 Feb 9, 2026
a01b2a7
#15 feat: SelectableItem className으로 오버라이딩 가능하도록
suminb99 Feb 9, 2026
64a9ec4
#15 chore: dnd-kit 관련 패키지 설치
suminb99 Feb 9, 2026
0e17edf
#15 style: shadow custom variant 추가
suminb99 Feb 9, 2026
4e81014
#15 feat: 응답 데이터 과제 배열 아이템 추가
suminb99 Feb 9, 2026
57f9029
#15 feat: 문제 등록 섹션 추가
suminb99 Feb 9, 2026
c0e321e
#15 feat: 드래그 및 정렬 가능한 문제 아이템 컴포넌트 추가
suminb99 Feb 9, 2026
38e8fd7
Merge branch 'develop' into feature/38-dashboard-api
suminb99 Feb 11, 2026
7584993
#15 refactor: addIcon 색상 currentColor 적용 및 Button none 사이즈 수정
suminb99 Feb 11, 2026
94cb995
#15 style: 단원 편집 폼 레이아웃 및 스크롤 개선
suminb99 Feb 11, 2026
ca70b6a
Merge branch 'feature/38-dashboard-api' into feature/44-unit-page-api
suminb99 Feb 11, 2026
2f1ea99
#44 feat: 강의별 전체 단원 조회 api
suminb99 Feb 11, 2026
5b292f5
#44 feat: 특정 단원 조회 api
suminb99 Feb 11, 2026
5700500
#44 feat: 단원 삭제 api
suminb99 Feb 11, 2026
1b5573c
#44 feat: 단원 조회 관련 쿼리 옵션스 추가
suminb99 Feb 11, 2026
a1d8cf2
#44 feat: 단원 폼에 zod 스키마 기반 유효성 검증 적용
suminb99 Feb 11, 2026
291b3c1
#44 feat: Button 컴포넌트에 formID prop 추가
suminb99 Feb 11, 2026
e280297
#44 feat: 단원 페이지에 동적 라우팅 및 전체 단원 조회 연동
suminb99 Feb 11, 2026
a0392e9
#44 fix: EmptyState 컴포넌트에서 불필요한 text-center 스타일 제거
suminb99 Feb 11, 2026
54c9f37
#44 feat: 단일 단원 조회 API 반환 타입 수정 및 nullable 처리
suminb99 Feb 11, 2026
da1ce82
#44 feat: 단원 선택 상태 관리 및 단일 단원 조회 API 연동
suminb99 Feb 11, 2026
8bbb2c1
#44 feat: 단원 목록에 선택 상태 UI 및 클릭 핸들러 추가
suminb99 Feb 11, 2026
0e754e9
#44 feat: 단원 폼에 조회 데이터 바인딩 및 문제 등록 섹션 리팩토링
suminb99 Feb 11, 2026
944d864
#44 style: 레이아웃 너비 및 정렬 스타일 조정
suminb99 Feb 13, 2026
e3bb94d
#44 feat: 단원 추가/편집 모드 분리 및 단원 인덱스 관리 기능 구현
suminb99 Feb 13, 2026
2e0944b
#44 refactor: Button 스타일 변수 export 처리 - 외부 사용 가능
suminb99 Feb 13, 2026
2678611
#44 fix: 과제 선택 페이지 정적 경로로 변경
suminb99 Feb 13, 2026
ee62253
#44 feat: 단원 생성 API 및 쿼리 옵션 추가
suminb99 Feb 13, 2026
40dbbaa
#44 feat: 단원 생성 mutation 연동 및 UI 바인딩
suminb99 Feb 13, 2026
5243442
#44 feat: 단원 생성 후 단원 목차 갱신 처리
suminb99 Feb 13, 2026
6c0812c
#44 refactor: 단원 쿼리 옵션을 unitQueries 객체로 통합
suminb99 Feb 13, 2026
2a16b75
#44 refactor: queryKey 네이밍 및 구조 정리
suminb99 Feb 13, 2026
8585c2c
#47 refactor: 공통 컴포넌트를 shared/ui로 이동 (components, layout 제거)
JiiminHa Feb 15, 2026
8594c59
#47 refactor: AssignmentFormLayout을 widgets로 이동, mock 데이터를 shared/moc…
JiiminHa Feb 15, 2026
dce9690
#47 refactor: pages를 역할별로 분리 (student/, admin/, common/)
JiiminHa Feb 15, 2026
b86a73c
#47 refactor: userType 동기화 로직을 useSyncUserRole 훅으로 분리
JiiminHa Feb 15, 2026
45c5434
#47 chore: 사용하지 않는 레거시 타입/유틸/훅 제거
JiiminHa Feb 15, 2026
2709e89
#47 refactor: 공용 UI import 경로를 shared로 정리
JiiminHa Feb 15, 2026
039403b
#47 fix: 코드 리뷰 수정 사항 반영
JiiminHa Feb 17, 2026
b80cdde
Merge pull request #48 from 2025-snowCode/refactor/47-fsd
JiiminHa Feb 18, 2026
37452f4
fix: 빌드 오류 해결 (FSD 구조 반영)
JiiminHa Feb 19, 2026
b8f84d9
fix: 빌드 오류 수정
JiiminHa Feb 19, 2026
87b6617
fix: 빌드 오류 해결을 위한 순환 참조 제거
JiiminHa Feb 19, 2026
8c5b86b
#49 chore: CI 파이프라인 업데이트
JiiminHa Feb 19, 2026
ba049f8
#49 chore: CI 파이프라인 수정 사항 반영
JiiminHa Feb 19, 2026
f50c120
#49 chore: 린트 에러 수정
JiiminHa Feb 19, 2026
b295670
#49 ci: Release Drafter 설정 추가
JiiminHa Feb 19, 2026
f736c0c
#49 refactor: 코드래빗 수정사항 반영
JiiminHa Feb 19, 2026
d576640
#49 fix: 빌드 오류 수정
JiiminHa Feb 19, 2026
3174240
#49 chore: 코드래빗 제안 사항 반영
JiiminHa Feb 19, 2026
80894e1
#49 chore: 팀 컨벤션 맞춰서 수정
JiiminHa Feb 19, 2026
f55ac76
chore: 디폴트 브랜치 설정을 위한 .github 폴더 우선 반영
JiiminHa Feb 19, 2026
8b2bc9b
Merge pull request #50 from 2025-snowCode/chore/49-setup-cicd
JiiminHa Feb 20, 2026
e021aa3
#44 feat: 단원 수정·삭제 API 및 mutation 옵션 추가
suminb99 Feb 22, 2026
55ebf7a
#44 refactor: 단원 페이지 상태 관리 및 CRUD 전체 연동
suminb99 Feb 22, 2026
96c12c1
#44 feat: 단원 CRUD 핸들러 버튼 연동 및 적용
suminb99 Feb 22, 2026
067b95a
#44 fix: barrel export 방식 제거
suminb99 Feb 22, 2026
85e674f
#44 refactor: unit entity 타입 분리 및 파일명 개선
suminb99 Feb 22, 2026
eb927e1
#44 refactor: 단원 에디터 페이지 폴더 구조 및 파일명 개선
suminb99 Feb 22, 2026
ffb98f9
Merge branch 'develop' into feature/44-unit-page-api
suminb99 Feb 22, 2026
8500939
#44 chore: 스타일 파일 분리 및 import 경로 정리
suminb99 Feb 23, 2026
2a88f6d
#44 chore: 단원 페이지 admin 블록 내부로 이동
suminb99 Feb 23, 2026
0b37ab3
#44 fix: unitId 타입 및 dnd-kit 이벤트 타입 명시화
suminb99 Feb 23, 2026
324f8c3
#44 fix: 단원 폼 id unitIndex 기반 설정
suminb99 Feb 23, 2026
4144562
#44 chore: zod import 방식 통일 및 주석 오타 수정
suminb99 Feb 23, 2026
9742a09
#44 fix: 임시 주석 처리
suminb99 Feb 23, 2026
2548c66
#44 fix: 파라미터 타입 수정
suminb99 Feb 23, 2026
6d7d3ea
#44 fix: pnpm-lock.yaml 갱신
suminb99 Feb 23, 2026
6ffba75
#44 fix: 타입 검사 강제 통과
suminb99 Feb 23, 2026
b16c8d7
#44 fix: zod 버전 downgrade
suminb99 Feb 23, 2026
e024658
#55 ci: Vercel 빌드 사전 검증 추가
JiiminHa Feb 26, 2026
fc59a1e
#55 ci: Vercel preview 빌드 사전 검증 추가
JiiminHa Feb 26, 2026
894991c
#55 ci: release 브랜치 기준으로 릴리즈 생성 로직 수정
JiiminHa Feb 26, 2026
b79a118
#55 ci: release 브랜치 기준으로 릴리즈 생성 로직 수정
JiiminHa Feb 26, 2026
8ac2727
Revert "#55 ci: release 브랜치 기준으로 릴리즈 생성 로직 수정"
JiiminHa Feb 26, 2026
f7661bd
Merge pull request #51 from 2025-snowCode/feature/44-unit-page-api
suminb99 Feb 26, 2026
da21284
Merge pull request #56 from 2025-snowCode/ci/vercel-build
JiiminHa Feb 26, 2026
0910751
Merge remote-tracking branch 'origin/main' into release
JiiminHa Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,13 @@ jobs:
VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }}
VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }}
VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }}

- name: Pull Vercel Environment
run: npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}

- name: Simulate Vercel Build
run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }}
env:
VITE_KAKAO_REST_API_KEY: ${{ secrets.VITE_KAKAO_REST_API_KEY }}
VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }}
VITE_API_BASE_URL: ${{ secrets.VITE_API_BASE_URL }}
5 changes: 1 addition & 4 deletions .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ on:
branches:
- release/*
- main
# PR 이벤트 추가로 자동화 범위 확대
pull_request:
types: [opened, reopened, synchronize]

permissions:
contents: write
Expand All @@ -19,7 +16,7 @@ jobs:
steps:
# Checkout 단계 제거 (불필요한 작업 생략)
- name: Update Draft Release
if: startsWith(github.ref, 'refs/heads/release/') || github.event_name == 'pull_request'
if: startsWith(github.ref, 'refs/heads/release/')
uses: release-drafter/release-drafter@v6
with:
config-name: template/release-drafter.yml
Expand Down
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="/src/style.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@hookform/resolvers": "^5.2.2",
"@tailwindcss/vite": "^4.1.11",
"@tanstack/react-query": "^5.90.20",
"axios": "^1.13.4",
Expand All @@ -22,6 +26,7 @@
"tailwind-merge": "^3.4.0",
"tailwind-variants": "^3.2.2",
"tailwindcss": "^4.1.11",
"zod": "^3.22.0",
"zustand": "^5.0.10"
},
"devDependencies": {
Expand Down
2,454 changes: 1,127 additions & 1,327 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

26 changes: 10 additions & 16 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {BrowserRouter, Routes, Route, useLocation} from 'react-router-dom';
import Layout from '@/layout/Layout';
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Layout from '@/shared/ui/Layout';
import LandingPage from '@/pages/common/LandingPage';
import UserIdInputPage from '@/pages/common/UserIdInputPage';
import Dashboard from '@/pages/dashboard/Dashboard';
Expand All @@ -11,21 +11,11 @@ import StudentManagementPage from '@/pages/admin/student/StudentManagementPage';
import StudentProfilePage from '@/pages/admin/student/StudentProfilePage';
import KakaoCallbackPage from '@/pages/common/KakaoCallbackPage';
import PrivateRoute from '@/widgets/private-route/ui/PrivateRoute';
import {useEffect} from 'react';
import {useUserStore} from '@/entities/auth/model/useUserStore';
import {useSyncUserRole} from '@/features/auth/sync-user-role/model/useSyncUserRole';
import UnitEditorPage from '@/pages/unit-editor/UnitEditorPage';

const AppRoutes = () => {
const {pathname} = useLocation();
const {setUserType} = useUserStore();

useEffect(() => {
const userType = pathname.startsWith('/admin')
? 'admin'
: pathname.startsWith('/student')
? 'student'
: 'guest';
setUserType(userType);
}, [pathname, setUserType]);
useSyncUserRole();

return (
<Routes>
Expand All @@ -52,14 +42,18 @@ const AppRoutes = () => {
path='assignments/create'
element={<AssignmentCreatePage />}
/>
<Route path='assignments/:id' element={<AssignmentSelectPage />} />
<Route
path='assignments/select'
element={<AssignmentSelectPage />}
/>
<Route path='courses/:id' element={<CourseOverviewPage />} />
<Route path='courses/create' element={<CourseCreatePage />} />
<Route path='student' element={<StudentManagementPage />} />
<Route
path='student/profile/:studentId'
element={<StudentProfilePage />}
/>
<Route path='units/:id' element={<UnitEditorPage />} />
</Route>
</Route>
</Route>
Expand Down
4 changes: 2 additions & 2 deletions src/assets/svg/addIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/svg/binIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 0 additions & 56 deletions src/components/admin/assignments/AssignmentCard.tsx

This file was deleted.

36 changes: 0 additions & 36 deletions src/components/common/ActionButton.tsx

This file was deleted.

11 changes: 0 additions & 11 deletions src/components/common/IconButton.tsx

This file was deleted.

40 changes: 0 additions & 40 deletions src/components/common/SelectableItem.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/entities/assignment/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import type {SubmissionStatus} from '@/shared/model/common';
export interface Assignment {
id: number;
title: string;
submittedStatus: SubmissionStatus;
submittedStatus?: SubmissionStatus;
}
13 changes: 9 additions & 4 deletions src/entities/course/model/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type {Assignment} from '@/entities/assignment/model/types';
export type {Assignment};
import type {ApiResponse, SemesterCode} from '@/shared/model/common';
export type {SemesterCode, SubmissionStatus} from '@/shared/model/common';



/**
* 일정(Schedule) 인터페이스 정의
Expand Down Expand Up @@ -95,3 +91,12 @@ export type CourseOptionsResponse = ApiResponse<{
count: number;
courses: DashboardCourse[];
}>;

// 단원 조회-생성 페이지 응답 타입 정의 - 단일 단원
export type SingleUnitResponse = ApiResponse<Unit>;

// 단원 조회-생성 페이지 응답 타입 정의 - 전체 단원 목록
export type AllUnitsResponse = ApiResponse<{
count: number;
units: Pick<Unit, 'id' | 'title' | 'assignmentCount'>[];
}>;
2 changes: 1 addition & 1 deletion src/entities/student/ui/AssignmentProgressCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {Student, ProgressStatus} from '../model/types';
import {ProgressIndicators} from '@/components/common/ProgressIndicators';
import {ProgressIndicators} from '@/shared/ui/ProgressIndicators';
import Correct from '@/assets/svg/correct.svg?react';
import Incorrect from '@/assets/svg/incorrect.svg?react';
import Unsubmitted from '@/assets/svg/unsubmitted.svg?react';
Expand Down
2 changes: 1 addition & 1 deletion src/entities/student/ui/StudentProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ProfileImage from '@/assets/svg/profileImage.svg?react';
import ChatIcon from '@/assets/svg/chatIcon.svg?react';
import MailIcon from '@/assets/svg/mailIcon.svg?react';
import Button from '@/components/common/Button';
import Button from '@/shared/ui/button/Button';

interface StudentProfileProps {
name: string;
Expand Down
4 changes: 2 additions & 2 deletions src/entities/student/ui/StudentTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Checkbox} from '@/components/common/Checkbox';
import {ProgressIndicators} from '@/components/common/ProgressIndicators';
import {Checkbox} from '@/shared/ui/checkbox/Checkbox';
import {ProgressIndicators} from '@/shared/ui/ProgressIndicators';
import {useState, useEffect} from 'react';
import {Link} from 'react-router-dom';
import type {Student} from '@/entities/student/model/types';
Expand Down
46 changes: 46 additions & 0 deletions src/entities/unit/api/unitApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {privateAxios} from '@/shared/api/axiosInstance';
import type {TUnitFormSchema} from '../model/types';
import type {ApiResponse} from '@/shared/model';
import type {AllUnitsResponse, Unit} from '@/entities/course/model/types';

// 강의별 전체 단원 조회
export const getAllUnitsByCourseId = async (
courseId: number
): Promise<AllUnitsResponse> => {
const response = await privateAxios.get(`/courses/${courseId}/units`);
return response.data;
};

// 단일 단원 조회
export const getUnitById = async (
unitId: number | null
): Promise<ApiResponse<Unit>> => {
const response = await privateAxios.get(`/units/${unitId}`);
return response.data;
Comment on lines +15 to +19
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

null unitId가 그대로 API 경로로 들어가는 케이스를 차단해주세요.

Line [16]-Line [19]에서 unitIdnull이면 /units/null 요청이 발생합니다. 조회 실패를 런타임까지 미루지 말고 함수 레벨에서 막는 게 안전합니다.
참고: TypeScript null 안전성 가이드 — https://www.typescriptlang.org/docs/handbook/2/narrowing.html

수정 제안
-export const getUnitById = async (
-  unitId: number | null
-): Promise<ApiResponse<Unit>> => {
+export const getUnitById = async (
+  unitId: number
+): Promise<ApiResponse<Unit>> => {
   const response = await privateAxios.get(`/units/${unitId}`);
   return response.data;
 };

또는 호출부 계약상 nullable 유지가 필요하다면:

 export const getUnitById = async (
   unitId: number | null
 ): Promise<ApiResponse<Unit>> => {
+  if (unitId == null) {
+    throw new Error('unitId is required');
+  }
   const response = await privateAxios.get(`/units/${unitId}`);
   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.

Suggested change
export const getUnitById = async (
unitId: number | null
): Promise<ApiResponse<Unit>> => {
const response = await privateAxios.get(`/units/${unitId}`);
return response.data;
export const getUnitById = async (
unitId: number
): Promise<ApiResponse<Unit>> => {
const response = await privateAxios.get(`/units/${unitId}`);
return response.data;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/entities/unit/api/unitApi.ts` around lines 15 - 19, getUnitById currently
allows unitId to be null which results in requests to "/units/null"; update
getUnitById to guard against null by validating unitId at the start of the
function (in function getUnitById) and immediately reject/throw a descriptive
error (or return a failed Promise<ApiResponse<Unit>>) when unitId is
null/undefined, so the HTTP call to privateAxios.get(`/units/${unitId}`) is
never made; alternatively, if nullable must be preserved by contract, narrow the
type inside getUnitById (e.g., early return when unitId == null) and document
the behavior.

};

// 단원 삭제
export const deleteUnit = async (
unitId: number
): Promise<ApiResponse<string>> => {
const response = await privateAxios.delete(`/units/${unitId}`);
return response.data;
};

// 단원 생성
export const createUnit = async (
courseId: number,
unit: TUnitFormSchema
): Promise<ApiResponse<Unit>> => {
const response = await privateAxios.post(`/units/${courseId}`, unit);
return response.data;
Comment on lines +31 to +36
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all unit API endpoints
echo "=== Unit API endpoints ==="
rg -nP --type=ts "privateAxios\.(get|post|put|delete)\(" src/entities/unit -C2

echo -e "\n=== Course-Unit endpoint patterns ==="
rg -nP --type=ts "/courses/\$\{[^}]+\}/units|/units/\$\{[^}]+\}" src -C2

echo -e "\n=== All unit endpoint patterns ==="
rg -nP --type=ts "/units" src -C1

Repository: 2025-snowCode/snowCode-Client

Length of output: 3317


생성 엔드포인트의 경로를 목록 조회와 일치시켜 주세요.

같은 파일에서 목록 조회는 GET /courses/${courseId}/units (라인 10)인데, 생성은 POST /units/${courseId} (라인 35)로 경로 패턴이 다릅니다. RESTful 컨벤션에 따르면 같은 리소스 컬렉션의 조회와 생성 작업은 동일한 경로를 사용해야 합니다.

제안: createUnit 함수의 엔드포인트를 /courses/${courseId}/units로 변경하여 일관성을 맞춰주세요. 현재 상태로는 백엔드 라우팅이 POST /units/${courseId} 를 지원하지 않으면 404/405 에러가 발생합니다.

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

In `@src/entities/unit/api/unitApi.ts` around lines 31 - 36, The createUnit
function is calling the wrong endpoint path; update the POST in createUnit so it
uses the same resource path as the list call (i.e. POST to
`/courses/${courseId}/units`) instead of `/units/${courseId}`; modify the
privateAxios.post call inside createUnit to target `/courses/${courseId}/units`
so create and list use a consistent RESTful collection path.

};

// 단원 수정
export const updateUnit = async (
unitId: number,
unit: TUnitFormSchema
): Promise<ApiResponse<Unit>> => {
const response = await privateAxios.put(`/units/${unitId}`, unit);
return response.data;
};
24 changes: 24 additions & 0 deletions src/entities/unit/api/unitMutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type {TUnitFormSchema} from '../model/types';
import {createUnit, deleteUnit, updateUnit} from './unitApi';

export const unitMutations = {
// 단원 추가 뮤테이션 옵션
createUnit: {
mutationKey: ['createUnit'],
mutationFn: ({courseId, unit}: {courseId: number; unit: TUnitFormSchema}) =>
createUnit(courseId, unit),
},

// 단원 수정 뮤테이션 옵션
updateUnit: {
mutationKey: ['updateUnit'],
mutationFn: ({unitId, unit}: {unitId: number; unit: TUnitFormSchema}) =>
updateUnit(unitId, unit),
},

// 단원 삭제 뮤테이션 옵션
deleteUnit: {
mutationKey: ['deleteUnit'],
mutationFn: (unitId: number) => deleteUnit(unitId),
},
};
Loading