Skip to content

Conversation

@JiiminHa
Copy link
Contributor

@JiiminHa JiiminHa commented Jan 6, 2026

⚙️ Related ISSUE Number

close #13



📄 Work Description

1. 자산 및 아이콘 관리

  • SVG 컴포넌트 삭제: src/assets/svg 폴더 내의 모든 SVG 리액트 컴포넌트 파일과 index.ts의 export 문을 삭제하여 불필요하거나 중복된 코드를 제거했습니다.
  • 임포트 방식 변경: AssignmentCard.tsx 등에서 SVG를 가져올 때, public/svg 경로에서 ?react 접미사를 사용하여 리액트 컴포넌트처럼 직접 임포트하도록 수정했습니다.

2. 라우팅 및 페이지 구조

  • 경로 최적화: App.tsx에서 임포트 경로의 대소문자 표기를 통일하고, 라우트 경로(path)에서 선행 슬래시(/)를 제거하여 유지보수성을 높였습니다.
  • 관리자 기능 추가: 과제 생성, 코스 생성, 학생 관리 등 관리자 섹션의 내비게이션을 위한 새로운 관리자용 라우트를 추가했습니다.

3. 개발 도구(Tooling)

  • 코드 포맷팅: prettierprettier-plugin-tailwindcss를 개발 의존성(dev dependency)으로 추가했습니다. 이를 통해 일관된 코드 스타일을 유지하고, 특히 Tailwind CSS 클래스 정렬을 자동화했습니다.

4. 컴포넌트 개선

  • Layout 확장: AssignmentFormLayout 컴포넌트에 titleExtra 속성(prop)을 추가했습니다. 이를 통해 제목 옆에 버튼이나 아이콘 등 추가적인 요소를 유연하게 배치할 수 있습니다.



📷 Screenshot



💬 To Reviewers



🔗 Reference

Summary by CodeRabbit

  • New Features

    • Added an admin Student Management page.
  • Improvements

    • Reorganized admin routes and added student-list navigation with course context.
    • Form layouts support flexible header content; buttons now accept click handlers.
    • Icon handling moved to optimized public SVGs; legacy icon barrel exports removed.
    • Added CSS status color variables and stronger component typings.
  • Chores

    • Developer tooling added: Prettier (with Tailwind plugin), commitlint, and a commit-msg hook; code-review config added.

✏️ Tip: You can customize this high-level summary in your review settings.

@JiiminHa JiiminHa requested a review from suminb99 January 6, 2026 06:01
@JiiminHa JiiminHa self-assigned this Jan 6, 2026
@JiiminHa JiiminHa added the 🧹 chore 프로젝트 설정 / 빌드 / 패키지 관리 label Jan 6, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
duplicated mapping key in ".coderabbit.yaml" (24:3)

 21 |   fail_commit_status: false
 22 |   abort_on_close: true
 23 |   high_level_summary_in_walkthrou ...
 24 |   high_level_summary_placeholder: ...
--------^
 25 |   collapse_walkthrough: true
 26 | 
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Removes many local React SVG components and their barrel exports, swaps imports to public /svg assets, adds Prettier + tailwind plugin and commitlint/Husky hooks, introduces typed navigation/layout changes, adds StudentManagementPage and admin routes, and small component API updates (e.g., Button, AssignmentFormLayout, CourseActionsBar).

Changes

Cohort / File(s) Summary
SVG component deletions
src/assets/svg/AddIcon.tsx, src/assets/svg/ArrowdownIcon.tsx, src/assets/svg/ArrowleftIcon.tsx, src/assets/svg/ArrowrightIcon.tsx, src/assets/svg/ChatIcon.tsx, src/assets/svg/Chevrondown.tsx, src/assets/svg/DeleteIcon.tsx, src/assets/svg/DragAndDropIcon.tsx, src/assets/svg/EditIcon.tsx, src/assets/svg/EllipsisIcon.tsx, src/assets/svg/File.tsx, src/assets/svg/NotificationIcon.tsx, src/assets/svg/SignoutIcon.tsx, src/assets/svg/SingleEllipsisIcon.tsx, src/assets/svg/UserIcon.tsx
Deleted 15 React SVG component modules and their default exports.
Barrel exports removed
src/assets/svg/index.ts
Removed re-exports for the deleted SVG components.
SVG import migration (usage sites)
src/components/.../AssignmentCard.tsx, src/components/.../AssignmentPageLayout.tsx, src/components/.../CourseSelector.tsx, src/components/.../FileUpload.tsx, src/components/.../LabeledDropdown.tsx, src/components/common/Dashboard/CourseCard.tsx, src/components/common/Dashboard/CourseList.tsx, src/pages/common/LandingPage.tsx, src/pages/common/UserIdInputPage.tsx
Replaced local barrel/named SVG imports with direct public /svg/...?.react default imports (SVGR-style) at usage sites.
Component API & behavior changes
src/components/admin/assignments/AssignmentFormLayout.tsx, src/components/common/CourseOverview/CourseActionsBar.tsx, src/components/common/Button.tsx, src/components/common/CourseOverview/CourseHero.tsx, src/components/common/CourseOverview/EmptyCourse.tsx, src/components/common/CourseOverview/CourseStat.tsx
Added titleExtra?: React.ReactNode to AssignmentFormLayout; extended CourseActionsBar props (title, section) and added navigation to /admin/student; Button now accepts onClick; small className/prop wiring tweaks.
Layout typing & navigation
src/layout/Layout.tsx, src/components/common/IconButton.tsx
Introduced UserType and NavButton types; typed getNavigationButtons and NavigationBar props; switched some asset imports to public SVGs.
Student management & routing
src/pages/admin/student/studentManagementPage.tsx, src/App.tsx
Added StudentManagementPage and wired admin routes (admin/student, admin/assignments/create, admin/courses/create); normalized nested route paths and updated imports.
Tooling & config
package.json, .prettierrc, .husky/commit-msg, commitlint.config.cjs
Added devDependencies (@commitlint/cli, @commitlint/config-conventional, prettier, prettier-plugin-tailwindcss), added Prettier tailwind config, and added commit-msg Husky hook + commitlint config.
Codebase import aliasing
many files under src/components/**, src/pages/**, src/utils/** (e.g., @/...)
Replaced numerous relative imports with project alias imports (@/...) for consistency.
Styling tokens
src/index.css
Added status CSS variables: --color-status-green, --color-status-yellow, --color-status-red.
Minor page/component cleanups
src/pages/admin/assignments/AssignmentCreatePage.tsx, src/pages/admin/assignments/AssignmentSelectPage.tsx, src/pages/admin/assignments/AssignmentsPage.tsx
Unused param rename (ex_), removed linkedAssignments state/handler, adjusted layout prop usage and imports.
Repository automation config
.coderabbit.yaml
Added CodeRabbit review automation policy (localized rules, path-specific checks, tooling integration).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

🛠️ refactor

Suggested reviewers

  • suminb99

Poem

🐇 I hopped through code and moved each icon,
nudged routes, added lint for each commit—so spry—
I gave forms extra room to flaunt,
and left a prettier, tidier sky.
— a tidy rabbit's tiny try.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main refactoring changes: asset structure improvement, routing optimization, and Prettier introduction, matching the primary objectives of the PR.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #13: asset structure optimization (deleted unused SVG components, switched to ?react imports), routing improvements (unified casing, added admin routes), Prettier setup, titleExtra prop addition, and Git hooks/CodeRabbit configuration.
Out of Scope Changes check ✅ Passed All changes are aligned with issue #13 requirements. No out-of-scope modifications detected; changes include asset management refactoring, routing optimization, tooling additions, and component enhancements as specified.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@JiiminHa JiiminHa changed the title Refactor: 에셋 관리 구조 개선 및 라우팅 최적화 (Prettier 도입) #13 refactor: 에셋 관리 구조 개선 및 라우팅 최적화 (Prettier 도입) Jan 6, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/common/Dashboard/CourseList.tsx (1)

35-37: Remove commented code.

The commented onClickAdd function should either be implemented and connected to the Add button (lines 48-51), or removed entirely.

🤖 Fix all issues with AI Agents
In @package.json:
- Around line 30-31: The Prettier Tailwind plugin is installed (prettier and
prettier-plugin-tailwindcss) but your .prettierrc is missing the
tailwindStylesheet option required for Tailwind CSS v4 support; open .prettierrc
and add the tailwindStylesheet key with the path to your Tailwind entry file
(e.g., "src/index.css" or your actual entry) so prettier-plugin-tailwindcss can
correctly sort classes.

In @src/components/common/CourseOverview/CourseActionsBar.tsx:
- Around line 13-15: handleStudentListClick builds the student list URL by
directly interpolating title and section causing malformed URLs for values with
spaces or special characters; update handleStudentListClick to URL-encode the
query parameters (e.g., use encodeURIComponent on title and section or build the
query via URLSearchParams) before passing to navigate so the resulting
`/admin/student?course=...` value is properly escaped.

In @src/components/common/Dashboard/CourseList.tsx:
- Line 3: The import for AddIcon uses an incorrect /public/ prefix; update the
import in CourseList.tsx to remove the /public part so it imports from
'/svg/addIcon.svg?react' (i.e., change the AddIcon import statement to use the
root-served path), and check any other SVG imports in the file for the same
/public/ prefix and fix them similarly.

In @src/layout/Layout.tsx:
- Line 11: Remove the duplicate local type alias UserType in Layout.tsx and
instead import and reuse the canonical UserType defined in the Dashboard types
module (the types.ts that currently defines UserType). Replace the local
declaration "type UserType = 'admin' | 'student';" with an import like "import {
UserType } from '...types...';" (use the existing Dashboard types module), and
ensure any references in Layout.tsx continue to use UserType without changing
semantics.

In @src/pages/admin/student/studentManagementPage.tsx:
- Line 11: The className on the button element in studentManagementPage.tsx has
a leading space (' text-primary px-3...'); remove the leading whitespace so the
value begins with "text-primary..." to avoid issues with class parsing (locate
the button element that currently sets className to ' text-primary px-3 py-[6px]
rounded-4xl inline-flex h-8 justify-center items-center border border-primary'
and update it).

In @src/pages/common/LandingPage.tsx:
- Line 8: The SVG import paths use the `/public` prefix which breaks Vite
resolution; update imports like the ArrowrightIcon import (ArrowrightIcon in
LandingPage.tsx) to remove `/public` so they reference root-served assets (e.g.,
`/svg/arrowrightIcon.svg?react`) and apply the same change for all other SVG
imports across Layout.tsx, CourseCard.tsx, AssignmentCard.tsx, etc.; ensure the
query parameter `?react` remains and run the app to verify the modules resolve.
🧹 Nitpick comments (6)
src/components/common/IconButton.tsx (1)

1-11: Component looks good; consider adding common button props for flexibility.

The IconButton component is clean and simple. However, it lacks common button affordances such as onClick, disabled, and aria-label, which limits its reusability. If these are intentionally handled at the call site, that's fine, but consider extending the interface for better component flexibility.

🔎 Optional enhancement for broader button support

If needed in the future, you can extend the component to accept standard button attributes:

-interface IconButtonProps {
-  icon: React.ReactElement;
-}
-
-const IconButton = ({icon}: IconButtonProps) => {
-  return <button className='header-btn'>{icon}</button>;
+interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
+  icon: React.ReactElement;
+}
+
+const IconButton = ({icon, ...buttonProps}: IconButtonProps) => {
+  return <button className='header-btn' {...buttonProps}>{icon}</button>;
 };

This allows callers to pass onClick, aria-label, title, disabled, etc. as needed.

src/pages/admin/assignments/AssignmentsPage.tsx (1)

1-1: Consider replacing dummy data with a real API call.

The import references a dummy/response file, suggesting this is mock data. If this page is production-ready, consider replacing the hardcoded response with an actual API call or state management solution.

src/components/common/CourseOverview/EmptyCourse.tsx (1)

14-14: Consider whether CourseActionsBar should render in an empty course state.

Passing empty strings for title and section suggests these props may not be meaningful in this context. Consider either:

  1. Making title and section optional in CourseActionsBar and handling the empty/undefined case appropriately in its implementation, or
  2. Conditionally rendering CourseActionsBar only when there's actual course data to display.

This would better align the component's API with its semantic usage.

src/App.tsx (1)

11-11: Inconsistent filename casing for student management page.

The imported file studentManagementPage.tsx uses camelCase, while other admin page files in this project use PascalCase (e.g., AssignmentsPage.tsx, CourseCreatePage.tsx, AssignmentSelectPage.tsx). For consistency, consider renaming the file to StudentManagementPage.tsx.

src/pages/admin/student/studentManagementPage.tsx (2)

11-31: Initial UI scaffolding detected - consider implementing interactive functionality.

The course filter button (lines 11-13), search input (lines 15-20), and action handlers (lines 30-31) are currently non-functional placeholders. Based on the PR objectives mentioning "detailed tasks left as TODOs" for issue #13, this appears to be intentional initial scaffolding.

Consider adding:

  • onClick handler for the course filter button (possibly opening a dropdown)
  • State management and onChange handler for the search input
  • Implementation for onCancel and onConfirm handlers
  • Actual student management content to replace the placeholder

Would you like me to help generate the implementation for any of these interactive features, or would you prefer to track these as separate issues/TODOs?


15-20: Add accessible label for search input.

The search input uses only a placeholder for labeling, which is insufficient for accessibility. Screen readers may not properly announce the input's purpose.

🔎 Suggested accessibility improvements

Option 1: Visible label

+      <label htmlFor='student-search' className='sr-only'>
+        학번 검색
+      </label>
       <input
+        id='student-search'
         type='text'
         placeholder='학번을 검색하세요'
         className='border border-gray-300 rounded-lg px-4 py-2 pr-10 w-64'
       />

Option 2: aria-label

       <input
         type='text'
         placeholder='학번을 검색하세요'
+        aria-label='학번 검색'
         className='border border-gray-300 rounded-lg px-4 py-2 pr-10 w-64'
       />
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2db5fba and cf09fb8.

⛔ Files ignored due to path filters (3)
  • package-lock.json is excluded by !**/package-lock.json
  • public/svg/profileImage.svg is excluded by !**/*.svg
  • public/svg/search.svg is excluded by !**/*.svg
📒 Files selected for processing (40)
  • package.json
  • src/App.tsx
  • src/assets/svg/AddIcon.tsx
  • src/assets/svg/ArrowdownIcon.tsx
  • src/assets/svg/ArrowleftIcon.tsx
  • src/assets/svg/ArrowrightIcon.tsx
  • src/assets/svg/ChatIcon.tsx
  • src/assets/svg/Chevrondown.tsx
  • src/assets/svg/DeleteIcon.tsx
  • src/assets/svg/DragAndDropIcon.tsx
  • src/assets/svg/EditIcon.tsx
  • src/assets/svg/EllipsisIcon.tsx
  • src/assets/svg/File.tsx
  • src/assets/svg/NotificationIcon.tsx
  • src/assets/svg/SignoutIcon.tsx
  • src/assets/svg/SingleEllipsisIcon.tsx
  • src/assets/svg/UserIcon.tsx
  • src/assets/svg/index.ts
  • src/components/admin/assignments/AssignmentCard.tsx
  • src/components/admin/assignments/AssignmentFormLayout.tsx
  • src/components/admin/assignments/AssignmentPageLayout.tsx
  • src/components/admin/assignments/CourseSelector.tsx
  • src/components/admin/form/FileUpload.tsx
  • src/components/admin/form/LabeledDropdown.tsx
  • src/components/common/Button.tsx
  • src/components/common/CourseOverview/CourseActionsBar.tsx
  • src/components/common/CourseOverview/CourseHero.tsx
  • src/components/common/CourseOverview/CourseStat.tsx
  • src/components/common/CourseOverview/EmptyCourse.tsx
  • src/components/common/Dashboard/CourseCard.tsx
  • src/components/common/Dashboard/CourseList.tsx
  • src/components/common/IconButton.tsx
  • src/index.css
  • src/layout/Layout.tsx
  • src/pages/admin/assignments/AssignmentCreatePage.tsx
  • src/pages/admin/assignments/AssignmentSelectPage.tsx
  • src/pages/admin/assignments/AssignmentsPage.tsx
  • src/pages/admin/student/studentManagementPage.tsx
  • src/pages/common/LandingPage.tsx
  • src/pages/common/UserIdInputPage.tsx
💤 Files with no reviewable changes (17)
  • src/assets/svg/ChatIcon.tsx
  • src/assets/svg/EditIcon.tsx
  • src/assets/svg/AddIcon.tsx
  • src/assets/svg/SingleEllipsisIcon.tsx
  • src/assets/svg/File.tsx
  • src/pages/admin/assignments/AssignmentSelectPage.tsx
  • src/assets/svg/ArrowdownIcon.tsx
  • src/assets/svg/DragAndDropIcon.tsx
  • src/assets/svg/ArrowleftIcon.tsx
  • src/assets/svg/SignoutIcon.tsx
  • src/assets/svg/EllipsisIcon.tsx
  • src/assets/svg/UserIcon.tsx
  • src/assets/svg/NotificationIcon.tsx
  • src/assets/svg/DeleteIcon.tsx
  • src/assets/svg/index.ts
  • src/assets/svg/ArrowrightIcon.tsx
  • src/assets/svg/Chevrondown.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/App.tsx:6-11
Timestamp: 2025-07-16T12:33:43.867Z
Learning: JiiminHa prefers hierarchical routing structure with role-based path organization: common routes at root level (/), student-specific routes under /student prefix, and admin-specific routes under /admin prefix, using nested routes with a shared Layout component for consistent UI patterns.
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:00:01.926Z
Learning: This project uses svgr for automatic SVG to React component conversion. Running `npm run svgr` automatically converts all svgr files to React component format and handles camelCase conversion for SVG attributes (e.g., stroke-width → strokeWidth).
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:6-18
Timestamp: 2025-07-13T00:25:00.538Z
Learning: User JiiminHa prefers using semantic HTML tags over excessive div usage for better code structure and accessibility in React components.
📚 Learning: 2025-07-13T00:27:31.464Z
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:10-10
Timestamp: 2025-07-13T00:27:31.464Z
Learning: Using TypeScript interfaces for React component props (like StudentHeaderProps) provides clear structure, improves readability, and makes components more maintainable and extensible for future development.

Applied to files:

  • src/components/admin/assignments/CourseSelector.tsx
  • src/components/admin/assignments/AssignmentCard.tsx
  • src/pages/admin/student/studentManagementPage.tsx
  • src/components/common/CourseOverview/CourseHero.tsx
  • src/components/common/Dashboard/CourseCard.tsx
  • src/layout/Layout.tsx
  • src/components/common/CourseOverview/CourseActionsBar.tsx
📚 Learning: 2025-07-16T13:14:38.834Z
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.

Applied to files:

  • src/components/admin/assignments/AssignmentCard.tsx
  • src/components/admin/form/FileUpload.tsx
📚 Learning: 2025-07-16T12:33:43.867Z
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/App.tsx:6-11
Timestamp: 2025-07-16T12:33:43.867Z
Learning: JiiminHa prefers hierarchical routing structure with role-based path organization: common routes at root level (/), student-specific routes under /student prefix, and admin-specific routes under /admin prefix, using nested routes with a shared Layout component for consistent UI patterns.

Applied to files:

  • src/App.tsx
🧬 Code graph analysis (2)
src/layout/Layout.tsx (1)
src/components/common/Dashboard/types.ts (1)
  • UserType (30-30)
src/App.tsx (2)
src/pages/common/UserIdInputPage.tsx (1)
  • UserIdInputPage (7-134)
src/pages/admin/student/studentManagementPage.tsx (1)
  • StudentManagementPage (5-34)
🔇 Additional comments (23)
src/components/common/CourseOverview/CourseStat.tsx (1)

13-13: LGTM! Prettier formatting applied correctly.

The Tailwind class reordering is the expected result of running prettier-plugin-tailwindcss (added in this PR). The change is purely cosmetic with no functional impact.

src/index.css (1)

51-53: LGTM! Status color tokens follow project conventions.

The new status color custom properties are well-named, use valid hex values, and are correctly placed within the @theme block for Tailwind v4. These likely support the student management UI features introduced in this PR.

src/pages/admin/assignments/AssignmentsPage.tsx (1)

2-14: LGTM!

The import path update correctly reflects the file reorganization, and the component logic is clean and straightforward.

src/components/common/Dashboard/CourseList.tsx (1)

48-51: Verify: Add button has no onClick handler.

The Add button is rendered for admin users but has no click handler attached. Is this intentional, or should it connect to the commented onClickAdd function?

src/components/admin/form/LabeledDropdown.tsx (2)

27-86: Component implementation looks solid — migration approach is cleaner than the previous svgr workflow.

The component logic is well-structured with proper state management, event handling, and accessibility considerations. Once the import path is corrected (see previous comment), the migration to direct SVG imports with ?react suffix is actually simpler than the old workflow requiring npm run svgr code generation.

Based on learnings, the previous workflow required placing SVGs in public/svg, running npm run svgr, then importing from src/assets/svg. This new approach is more direct and eliminates the code generation step.


2-2: No changes needed — import path is correct and consistent with the codebase.

The /public/svg/chevrondown.svg?react pattern is already established throughout the codebase. Multiple files (AssignmentCard.tsx, Layout.tsx, CourseSelector.tsx, FileUpload.tsx, and others) use this exact same import pattern. The vite-plugin-svgr configuration in vite.config.ts supports this approach, processing SVG files from the public directory at build/dev time with the ?react query parameter.

src/pages/admin/assignments/AssignmentCreatePage.tsx (1)

38-38: LGTM! Good practice for unused parameter.

Using _ to indicate the unused array element parameter improves code readability and follows common conventions.

src/components/admin/assignments/CourseSelector.tsx (1)

2-2: Verify the import path for public folder assets.

The import path includes the /public prefix, which is typically not needed when importing from Vite's public folder. This should likely be /svg/arrowdownIcon.svg?react instead. Please verify this works correctly in your build environment.

src/components/admin/assignments/AssignmentPageLayout.tsx (1)

5-5: Verify the import path for public folder assets.

The /public prefix in the import path may be incorrect for Vite's public folder handling. Standard Vite convention uses /svg/addIcon.svg?react without the /public prefix.

src/components/common/Dashboard/CourseCard.tsx (1)

2-2: Verify the import path for public folder assets.

Consistent with the other files in this PR, this import uses the /public prefix. In standard Vite setups, public folder assets are accessed from the root (e.g., /svg/ellipsisIcon.svg?react). Please confirm your Vite configuration supports this path pattern or adjust the imports accordingly.

src/components/admin/form/FileUpload.tsx (1)

3-3: LGTM! Consistent with project-wide SVG migration.

The import source change from local assets to public SVG path with ?react loader aligns with the broader migration strategy across the codebase. The component name change to FileIcon is also more descriptive.

Based on learnings, this pattern uses Vite's svgr loader to import SVGs as React components from the public directory.

Also applies to: 106-106

src/components/admin/assignments/AssignmentCard.tsx (1)

2-5: LGTM! SVG imports consistently migrated.

All four icon imports have been successfully migrated to the public SVG path pattern with the ?react loader, maintaining consistency with the broader refactoring effort across the codebase.

src/pages/common/UserIdInputPage.tsx (1)

5-5: LGTM! Icon import migrated correctly.

The ArrowleftIcon import follows the established public SVG path pattern, consistent with the project-wide migration strategy.

src/layout/Layout.tsx (3)

4-7: LGTM! Icon imports migrated to public SVG pattern.

All four icon imports successfully follow the public SVG path pattern with ?react loader, consistent with the project-wide migration.


9-9: React import is necessary for type usage.

While React 19's JSX transform doesn't require importing React for JSX, the import is needed here because React.ReactElement is used in the NavButton interface type definition (line 14).


13-16: Excellent type safety improvements!

The addition of the NavButton interface and comprehensive type annotations for getNavigationButtons, getWelcomeMessage, and NavigationBar significantly improves type safety and code maintainability.

Also applies to: 27-65

src/components/common/Button.tsx (1)

5-5: LGTM! onClick handler properly implemented.

The onClick prop is correctly typed as optional, properly destructured, and forwarded to the button element. This enables the Button component to support click handlers for navigation and other interactions.

Also applies to: 19-19, 22-22

src/App.tsx (1)

18-40: LGTM on routing structure improvements!

The removal of leading slashes from nested routes (e.g., userid instead of /userid) is correct for React Router v6, and the new admin routes for assignment creation, course creation, and student management are well-organized under the /admin prefix, following the hierarchical routing structure.

src/components/admin/assignments/AssignmentFormLayout.tsx (1)

5-5: LGTM on titleExtra prop addition!

The optional titleExtra prop is well-designed, allowing flexible composition of the title area. The flex layout implementation (lines 22-25) properly positions the title and extra content with appropriate spacing, and the prop being optional maintains backward compatibility with existing usages.

Also applies to: 13-13, 22-25

src/components/common/CourseOverview/CourseHero.tsx (1)

36-40: LGTM on CourseActionsBar props update!

The addition of title and section props to CourseActionsBar is correctly implemented, passing through the component's own props to provide necessary context to the actions bar. The conditional rendering logic remains appropriate for the admin active course scenario.

src/components/common/CourseOverview/CourseActionsBar.tsx (3)

1-1: LGTM!

The import statement is correct and follows React Router v6 conventions.


4-8: LGTM!

The TypeScript interface is well-structured and provides clear prop types. Based on learnings, using interfaces for React component props improves readability and maintainability.


22-22: LGTM!

The onClick handler is correctly wired to the button, assuming the URL encoding issue in handleStudentListClick is addressed.

import IconButton from '../components/common/IconButton';
import React from 'react';

type UserType = 'admin' | 'student';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Eliminate duplicate UserType definition.

The UserType type is already defined in src/components/common/Dashboard/types.ts (line 29). Import and reuse the existing type instead of redefining it to avoid code duplication and potential inconsistencies.

🔎 Proposed fix to import existing UserType
+import type {UserType} from '../components/common/Dashboard/types';
+
-type UserType = 'admin' | 'student';
-
 interface NavButton {
📝 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
type UserType = 'admin' | 'student';
import type {UserType} from '../components/common/Dashboard/types';
interface NavButton {
🤖 Prompt for AI Agents
In @src/layout/Layout.tsx around line 11, Remove the duplicate local type alias
UserType in Layout.tsx and instead import and reuse the canonical UserType
defined in the Dashboard types module (the types.ts that currently defines
UserType). Replace the local declaration "type UserType = 'admin' | 'student';"
with an import like "import { UserType } from '...types...';" (use the existing
Dashboard types module), and ensure any references in Layout.tsx continue to use
UserType without changing semantics.


const titleExtra = (
<div className='flex justify-between items-center flex-1'>
<button className=' text-primary px-3 py-[6px] rounded-4xl inline-flex h-8 justify-center items-center border border-primary'>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove leading space in className.

The className prop starts with a space: ' text-primary'. This leading whitespace should be removed as it can cause unexpected behavior or issues with certain CSS frameworks and class name processing.

🔎 Proposed fix
-      <button className=' text-primary px-3 py-[6px] rounded-4xl inline-flex h-8 justify-center items-center border border-primary'>
+      <button className='text-primary px-3 py-[6px] rounded-4xl inline-flex h-8 justify-center items-center border border-primary'>
📝 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
<button className=' text-primary px-3 py-[6px] rounded-4xl inline-flex h-8 justify-center items-center border border-primary'>
<button className='text-primary px-3 py-[6px] rounded-4xl inline-flex h-8 justify-center items-center border border-primary'>
🤖 Prompt for AI Agents
In @src/pages/admin/student/studentManagementPage.tsx around line 11, The
className on the button element in studentManagementPage.tsx has a leading space
(' text-primary px-3...'); remove the leading whitespace so the value begins
with "text-primary..." to avoid issues with class parsing (locate the button
element that currently sets className to ' text-primary px-3 py-[6px]
rounded-4xl inline-flex h-8 justify-center items-center border border-primary'
and update it).

@JiiminHa JiiminHa changed the title #13 refactor: 에셋 관리 구조 개선 및 라우팅 최적화 (Prettier 도입) #13 refactor: assets 관리 구조 개선 및 라우팅 최적화 (Prettier 도입) Jan 6, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/pages/admin/assignments/AssignmentSelectPage.tsx (3)

7-7: Add validation for the route parameter.

Number(useParams().id) will produce NaN if the id parameter is undefined, missing, or non-numeric. This will cause the course lookup (line 11) to fail silently, resulting in an empty fullCourses array and a broken UI.

🔎 Suggested fix with validation
  const AssignmentSelectPage = () => {
    // url에서 course id 가져오기
-   const courseId = Number(useParams().id);
+   const {id} = useParams();
+   const courseId = Number(id);
+   
+   if (!id || isNaN(courseId)) {
+     return <div>잘못된 강의 ID입니다.</div>;
+   }

10-17: Add error handling for course lookup failure.

If the course with the given courseId is not found, courseTitle will be undefined, causing the filter to return an empty array. This results in a blank page with no feedback to the user about why courses aren't displayed.

🔎 Suggested fix with error handling
  // 강의명 찾기
-  const courseTitle = coursesResponse.response.courses.find(
+  const course = coursesResponse.response.courses.find(
    (course) => course.id === courseId
-  )?.title;
+  );
+  
+  if (!course) {
+    return <div>해당 강의를 찾을 수 없습니다.</div>;
+  }

  // 기본 문제 목록
  const fullCourses = coursesResponse.response.courses.filter(
-    (course) => course.title === courseTitle
+    (c) => c.title === course.title
  );

19-25: Missing onLinkAssignments callback breaks selection tracking in selectMode.

The onLinkAssignments prop is defined in AssignmentPageLayout's interface (line 12) but is not destructured or forwarded to AssignmentList (line 33). When selectMode={true}, users can select assignments, but the selection callback will not be invoked because it's never passed down the component chain. This breaks the selection functionality that depends on onLinkAssignments being called in AssignmentCard.

Pass the onLinkAssignments prop to AssignmentList on line 33:

Fix
<AssignmentList 
  courses={courses} 
  selectMode={selectMode} 
  onLinkAssignments={onLinkAssignments}
/>
🤖 Fix all issues with AI Agents
In @src/components/common/CourseOverview/CourseActionsBar.tsx:
- Around line 13-15: The navigation URL in handleStudentListClick builds an
unencoded query string using title and section which breaks when those values
contain spaces or special characters; update handleStudentListClick to
URL-encode the parameters (e.g., use encodeURIComponent on title and section or
construct the query via URLSearchParams) and then call navigate with the encoded
query so navigate(`/admin/student?course=${encodedCourse}`) receives a valid,
safe URL.

In @src/components/common/CourseOverview/EmptyCourse.tsx:
- Line 14: The current EmptyCourse passes empty title/section to
CourseActionsBar which lets handleStudentListClick build a malformed URL via
navigate(`/admin/student?course=${title} (${section})`); fix by adding
validation inside CourseActionsBar: make title and section optional props, have
handleStudentListClick first check that title and section are non-empty (or
produce a safe fallback) and, if invalid, prevent navigation and disable or hide
the "학생 목록" button; alternatively, change EmptyCourse to not render
CourseActionsBar when title/section are empty so handleStudentListClick is never
invoked.

In @src/components/common/CourseOverview/UnitHeader.tsx:
- Around line 1-2: Duplicate import of UnitLabel in UnitHeader.tsx: remove the
redundant import statement so only a single import of UnitLabel remains (keep
the first import and delete the second) to resolve the redeclaration/compilation
error referencing UnitLabel in UnitHeader.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 573532b and 782a71f.

📒 Files selected for processing (27)
  • src/components/admin/assignments/AssignmentCard.tsx
  • src/components/admin/assignments/AssignmentPageLayout.tsx
  • src/components/admin/assignments/CourseSelector.tsx
  • src/components/admin/form/FileUpload.tsx
  • src/components/admin/form/LabeledDropdown.tsx
  • src/components/common/BaseHeader.tsx
  • src/components/common/CourseOverview/AssignmentItem.tsx
  • src/components/common/CourseOverview/AssignmentList.tsx
  • src/components/common/CourseOverview/CourseActionsBar.tsx
  • src/components/common/CourseOverview/CourseHero.tsx
  • src/components/common/CourseOverview/EmptyCourse.tsx
  • src/components/common/CourseOverview/SubmissionBadge.tsx
  • src/components/common/CourseOverview/UnitHeader.tsx
  • src/components/common/CourseOverview/dummy/types.ts
  • src/components/common/Dashboard/CourseCard.tsx
  • src/components/common/Dashboard/CourseList.tsx
  • src/components/common/Dashboard/ScheduleList.tsx
  • src/components/common/Dashboard/types.ts
  • src/layout/Layout.tsx
  • src/pages/admin/assignments/AssignmentSelectPage.tsx
  • src/pages/admin/assignments/AssignmentsPage.tsx
  • src/pages/admin/student/studentManagementPage.tsx
  • src/pages/common/CourseOverviewPage.tsx
  • src/pages/common/Dashboard.tsx
  • src/pages/common/LandingPage.tsx
  • src/pages/common/UserIdInputPage.tsx
  • src/utils/getSemesterLabel.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/components/common/Dashboard/CourseList.tsx
  • src/components/common/Dashboard/CourseCard.tsx
  • src/components/admin/assignments/AssignmentCard.tsx
  • src/components/admin/form/FileUpload.tsx
  • src/components/admin/form/LabeledDropdown.tsx
  • src/components/admin/assignments/AssignmentPageLayout.tsx
  • src/pages/admin/assignments/AssignmentsPage.tsx
  • src/pages/admin/student/studentManagementPage.tsx
  • src/pages/common/UserIdInputPage.tsx
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/App.tsx:6-11
Timestamp: 2025-07-16T12:33:43.867Z
Learning: JiiminHa prefers hierarchical routing structure with role-based path organization: common routes at root level (/), student-specific routes under /student prefix, and admin-specific routes under /admin prefix, using nested routes with a shared Layout component for consistent UI patterns.
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:00:01.926Z
Learning: This project uses svgr for automatic SVG to React component conversion. Running `npm run svgr` automatically converts all svgr files to React component format and handles camelCase conversion for SVG attributes (e.g., stroke-width → strokeWidth).
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:6-18
Timestamp: 2025-07-13T00:25:00.538Z
Learning: User JiiminHa prefers using semantic HTML tags over excessive div usage for better code structure and accessibility in React components.
📚 Learning: 2025-07-13T00:27:31.464Z
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:10-10
Timestamp: 2025-07-13T00:27:31.464Z
Learning: Using TypeScript interfaces for React component props (like StudentHeaderProps) provides clear structure, improves readability, and makes components more maintainable and extensible for future development.

Applied to files:

  • src/components/common/Dashboard/types.ts
  • src/layout/Layout.tsx
  • src/components/common/CourseOverview/AssignmentItem.tsx
  • src/components/common/BaseHeader.tsx
  • src/components/common/CourseOverview/AssignmentList.tsx
  • src/components/admin/assignments/CourseSelector.tsx
  • src/components/common/CourseOverview/CourseActionsBar.tsx
  • src/components/common/CourseOverview/UnitHeader.tsx
📚 Learning: 2025-07-16T13:14:38.834Z
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.

Applied to files:

  • src/pages/common/LandingPage.tsx
🧬 Code graph analysis (6)
src/components/common/Dashboard/types.ts (1)
src/components/admin/assignments/dummy/types.ts (1)
  • Course (10-18)
src/layout/Layout.tsx (2)
src/components/common/Dashboard/types.ts (1)
  • UserType (30-30)
src/App.tsx (1)
  • App (12-45)
src/components/common/CourseOverview/AssignmentItem.tsx (2)
src/components/admin/assignments/dummy/types.ts (2)
  • Assignment (4-8)
  • Course (10-18)
src/components/admin/assignments/AssignmentList.tsx (1)
  • AssignmentListProps (4-8)
src/components/common/CourseOverview/AssignmentList.tsx (2)
src/components/admin/assignments/dummy/types.ts (2)
  • Assignment (4-8)
  • Course (10-18)
src/components/admin/assignments/AssignmentList.tsx (1)
  • AssignmentListProps (4-8)
src/pages/common/CourseOverviewPage.tsx (2)
src/components/common/CourseOverview/CourseContent.tsx (1)
  • unit (11-13)
src/components/common/CourseOverview/Unit.tsx (1)
  • UnitProps (5-7)
src/components/admin/assignments/CourseSelector.tsx (1)
src/assets/svg/ArrowdownIcon.tsx (1)
  • props (3-16)
🪛 Biome (2.1.2)
src/components/common/CourseOverview/UnitHeader.tsx

[error] 2-2: Shouldn't redeclare 'UnitLabel'. Consider to delete it or rename it.

'UnitLabel' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (23)
src/components/admin/assignments/CourseSelector.tsx (1)

2-2: Import statement is correct.

The SVG filename casing matches exactly—public/svg/arrowdownIcon.svg exists and is properly referenced in the import. The migration to Vite's ?react suffix is correctly implemented with no issues.

src/pages/admin/assignments/AssignmentSelectPage.tsx (1)

1-3: The @ path alias is properly configured in vite.config.ts and both imported modules exist at their specified paths, so the imports are correct.

src/components/common/CourseOverview/SubmissionBadge.tsx (1)

1-4: LGTM! Import paths successfully migrated to alias-based paths.

The refactor from relative paths to @/ alias paths improves maintainability and aligns with the PR's objectives for path standardization.

src/components/common/CourseOverview/UnitHeader.tsx (1)

3-3: LGTM! Asset import successfully migrated to alias path.

The lock icon import now uses the @/ alias, consistent with the PR's path standardization objectives.

src/pages/common/LandingPage.tsx (2)

30-35: LGTM! Conditional rendering logic is correct.

The ternary operator formatting adjustment maintains the same logic while improving readability.


8-9: SVG import pattern is correctly configured.

The /svg/arrowrightIcon.svg?react import is valid and properly supported by the project. The vite-plugin-svgr (v4.3.0) is configured in vite.config.ts with icon: true optimization, the SVG file exists at public/svg/arrowrightIcon.svg, and Vite correctly serves files from the public folder at the /svg/ path. No action required.

src/components/common/Dashboard/types.ts (1)

1-1: LGTM! Type import successfully migrated to alias path.

The refactor to use @/ alias for the SemesterCode type import improves consistency with the broader codebase restructuring in this PR.

src/pages/common/CourseOverviewPage.tsx (1)

1-4: LGTM! All imports successfully migrated to alias-based paths.

The consistent use of @/ alias across all CourseOverview component imports improves code maintainability and aligns perfectly with the PR's path standardization objectives.

src/components/common/Dashboard/ScheduleList.tsx (1)

2-3: LGTM! Import path refactor aligns with PR objectives.

The conversion from relative to alias-based import paths is correct and consistent with the project-wide standardization. The SVG files are properly imported as regular images (without ?react suffix) since they're used in <img> elements.

src/components/common/CourseOverview/AssignmentItem.tsx (1)

1-1: LGTM! Type import path correctly updated.

The conversion to alias-based import path for the Assignment type is correct and aligns with the project-wide refactor.

src/components/common/CourseOverview/dummy/types.ts (1)

1-4: LGTM! Type import paths correctly updated.

The conversion to alias-based import paths for Assignment and SemesterCode types is correct and consistent with the project-wide import path standardization.

src/pages/common/Dashboard.tsx (1)

1-2: LGTM! Component import paths correctly updated.

The conversion to alias-based import paths for CourseList and ScheduleList components is correct and aligns with the project-wide refactor.

src/components/common/CourseOverview/EmptyCourse.tsx (1)

1-1: LGTM! Asset import path correctly updated.

The conversion to alias-based import path for the overview image is correct and consistent with the project-wide refactor.

src/utils/getSemesterLabel.ts (1)

1-1: LGTM! Import path refactored to use alias.

The change from relative to alias-based import path improves consistency across the codebase.

src/components/common/CourseOverview/CourseHero.tsx (2)

2-4: LGTM! Import paths refactored to use aliases.

The migration to alias-based imports improves consistency and maintainability.


36-40: CourseActionsBar properly accepts the new props.

The component signature has been correctly updated to accept title and section in addition to isActive. The interface definition (lines 4-8 of CourseActionsBar.tsx) matches the invocation, and the props are used to construct the student list navigation URL.

src/components/common/BaseHeader.tsx (1)

1-1: LGTM! Logo import refactored to use alias.

The change improves import consistency across the codebase.

src/components/common/CourseOverview/AssignmentList.tsx (1)

1-1: LGTM! Import path refactored to use alias.

The change aligns with the project-wide migration to alias-based imports.

src/layout/Layout.tsx (2)

3-9: LGTM! Import paths updated to use aliases and public SVG assets.

The migration to:

  • Alias-based imports (@/...) for components
  • Public SVG imports with ?react suffix (Vite's built-in feature)
  • Explicit React import for TypeScript typing

aligns with the PR's objective to optimize asset management and improve import consistency.


13-16: LGTM! TypeScript typing improvements enhance code quality.

The addition of:

  • NavButton interface for navigation items
  • Type annotations for getNavigationButtons, getWelcomeMessage, and NavigationBar

provides clear structure, improves type safety, and makes the component more maintainable. Based on learnings, this aligns with the project's preference for explicit TypeScript interfaces.

Also applies to: 27-42, 45-49, 52-58

src/components/common/CourseOverview/CourseActionsBar.tsx (3)

1-2: Good refactoring: absolute path alias and navigation hook.

The migration to absolute imports using the @ alias aligns with the PR objectives, and the useNavigate hook is correctly imported for programmatic navigation.


4-8: Excellent use of TypeScript interface for props.

The CourseActionsBarProps interface provides clear structure and type safety for the component. This aligns with project best practices for maintainable component APIs.


22-22: LGTM: onClick handler correctly bound.

The event handler is properly attached to the button component.

Comment on lines +13 to +15
const handleStudentListClick = () => {
navigate(`/admin/student?course=${title} (${section})`);
};
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

URL encoding issue remains unaddressed.

The previously flagged issue with unencoded query parameters is still present. Course titles or sections containing spaces, ampersands, or other special characters will create malformed URLs and break navigation.

🔎 Reminder: Use encodeURIComponent to fix
 const handleStudentListClick = () => {
-  navigate(`/admin/student?course=${title} (${section})`);
+  navigate(`/admin/student?course=${encodeURIComponent(`${title} (${section})`)}`);
 };

Alternatively, use URLSearchParams for cleaner query string construction:

 const handleStudentListClick = () => {
-  navigate(`/admin/student?course=${title} (${section})`);
+  const params = new URLSearchParams({ course: `${title} (${section})` });
+  navigate(`/admin/student?${params.toString()}`);
 };
📝 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
const handleStudentListClick = () => {
navigate(`/admin/student?course=${title} (${section})`);
};
const handleStudentListClick = () => {
navigate(`/admin/student?course=${encodeURIComponent(`${title} (${section})`)}`);
};
Suggested change
const handleStudentListClick = () => {
navigate(`/admin/student?course=${title} (${section})`);
};
const handleStudentListClick = () => {
const params = new URLSearchParams({ course: `${title} (${section})` });
navigate(`/admin/student?${params.toString()}`);
};
🤖 Prompt for AI Agents
In @src/components/common/CourseOverview/CourseActionsBar.tsx around lines
13-15, The navigation URL in handleStudentListClick builds an unencoded query
string using title and section which breaks when those values contain spaces or
special characters; update handleStudentListClick to URL-encode the parameters
(e.g., use encodeURIComponent on title and section or construct the query via
URLSearchParams) and then call navigate with the encoded query so
navigate(`/admin/student?course=${encodedCourse}`) receives a valid, safe URL.

아직 생성된 단원이 없어요
</span>
<CourseActionsBar isActive={false} />
<CourseActionsBar isActive={false} title='' section='' />
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 and display CourseActionsBar component definition
echo "=== CourseActionsBar Component Definition ==="
fd -t f "CourseActionsBar.tsx" --exec cat {}

echo -e "\n=== CourseActionsBar.tsx exists? ==="
fd -t f "CourseActionsBar"

echo -e "\n=== All CourseActionsBar usages ==="
rg -n -A2 -B1 '<CourseActionsBar' --type ts --type tsx

Repository: 2025-snowCode/snowCode-Client

Length of output: 1072


🏁 Script executed:

#!/bin/bash
# Fix the search with proper type syntax
echo "=== All CourseActionsBar usages ==="
rg -n -A2 -B1 '<CourseActionsBar'

echo -e "\n=== EmptyCourse.tsx content ==="
cat src/components/common/CourseOverview/EmptyCourse.tsx

echo -e "\n=== CourseActionsBar button onClick handling ==="
rg -n -A5 "handleStudentListClick" src/components/common/CourseOverview/CourseActionsBar.tsx

Repository: 2025-snowCode/snowCode-Client

Length of output: 1831


Fix button handler to prevent malformed navigation with empty props.

The CourseActionsBar component unconditionally attaches the handleStudentListClick onClick handler, which constructs a URL using title and section: navigate(/admin/student?course=${title} (${section})).

When EmptyCourse passes title='' and section='', clicking the "학생 목록" button will navigate to a malformed URL: /admin/student?course= ().

Solutions:

  • Add validation in handleStudentListClick to guard against empty values, or
  • Make title and section optional props and conditionally disable/hide the button when empty, or
  • Don't render CourseActionsBar in the empty state.
🤖 Prompt for AI Agents
In @src/components/common/CourseOverview/EmptyCourse.tsx around line 14, The
current EmptyCourse passes empty title/section to CourseActionsBar which lets
handleStudentListClick build a malformed URL via
navigate(`/admin/student?course=${title} (${section})`); fix by adding
validation inside CourseActionsBar: make title and section optional props, have
handleStudentListClick first check that title and section are non-empty (or
produce a safe fallback) and, if invalid, prevent navigation and disable or hide
the "학생 목록" button; alternatively, change EmptyCourse to not render
CourseActionsBar when title/section are empty so handleStudentListClick is never
invoked.

Comment on lines 1 to +2
import UnitLabel from './UnitLabel';
import lock from '../../../assets/images/lock.svg';
import UnitLabel from './UnitLabel';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove duplicate import statement.

Line 2 redeclares UnitLabel which is already imported on line 1. This will cause a compilation error.

🔎 Proposed fix
 import UnitLabel from './UnitLabel';
-import UnitLabel from './UnitLabel';
 import lock from '@/assets/images/lock.svg';
📝 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
import UnitLabel from './UnitLabel';
import lock from '../../../assets/images/lock.svg';
import UnitLabel from './UnitLabel';
import UnitLabel from './UnitLabel';
import lock from '@/assets/images/lock.svg';
🧰 Tools
🪛 Biome (2.1.2)

[error] 2-2: Shouldn't redeclare 'UnitLabel'. Consider to delete it or rename it.

'UnitLabel' is defined here:

(lint/suspicious/noRedeclare)

🤖 Prompt for AI Agents
In @src/components/common/CourseOverview/UnitHeader.tsx around lines 1-2,
Duplicate import of UnitLabel in UnitHeader.tsx: remove the redundant import
statement so only a single import of UnitLabel remains (keep the first import
and delete the second) to resolve the redeclaration/compilation error
referencing UnitLabel in UnitHeader.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI Agents
In @.husky/commit-msg:
- Line 15: The commitlint invocation uses an unquoted parameter $1 which can
break when the commit message file path contains spaces or special characters;
update the command in the .husky/commit-msg hook that calls commitlint (the line
starting with "if npx --no -- commitlint --edit $1; then") to quote the
parameter (use "$1") so the path is passed as a single argument to commitlint.
- Line 4: The commit-msg hook reads the file into commit_msg using an unquoted
$1 which breaks on paths with spaces and lacks validation; change the command to
use the quoted parameter and add checks that the parameter exists and the file
is readable before reading: validate that $1 is set, that [ -r "$1" ] succeeds,
log an error and exit non-zero if not, then assign commit_msg by reading the
quoted path (commit_msg=$(cat "$1")) to safely handle spaces and special
characters.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 782a71f and 11263f0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • .husky/commit-msg
  • commitlint.config.cjs
  • package.json
✅ Files skipped from review due to trivial changes (1)
  • commitlint.config.cjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/App.tsx:6-11
Timestamp: 2025-07-16T12:33:43.867Z
Learning: JiiminHa prefers hierarchical routing structure with role-based path organization: common routes at root level (/), student-specific routes under /student prefix, and admin-specific routes under /admin prefix, using nested routes with a shared Layout component for consistent UI patterns.
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:00:01.926Z
Learning: This project uses svgr for automatic SVG to React component conversion. Running `npm run svgr` automatically converts all svgr files to React component format and handles camelCase conversion for SVG attributes (e.g., stroke-width → strokeWidth).
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:6-18
Timestamp: 2025-07-13T00:25:00.538Z
Learning: User JiiminHa prefers using semantic HTML tags over excessive div usage for better code structure and accessibility in React components.

echo "📝 커밋 메시지를 검증합니다..."

# 커밋 메시지 읽기
commit_msg=$(cat $1)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Quote the parameter and add validation.

The unquoted $1 parameter can cause failures if the file path contains spaces or special characters. Additionally, there's no check that the parameter was provided or that the file exists.

🔎 Proposed fix
+# 파일 경로 검증
+if [ -z "$1" ] || [ ! -f "$1" ]; then
+  echo "❌ 커밋 메시지 파일을 찾을 수 없습니다."
+  exit 1
+fi
+
 # 커밋 메시지 읽기
-commit_msg=$(cat $1)
+commit_msg=$(cat "$1")

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @.husky/commit-msg around line 4, The commit-msg hook reads the file into
commit_msg using an unquoted $1 which breaks on paths with spaces and lacks
validation; change the command to use the quoted parameter and add checks that
the parameter exists and the file is readable before reading: validate that $1
is set, that [ -r "$1" ] succeeds, log an error and exit non-zero if not, then
assign commit_msg by reading the quoted path (commit_msg=$(cat "$1")) to safely
handle spaces and special characters.

fi

# commitlint 실행
if npx --no -- commitlint --edit $1; then
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Quote the parameter in commitlint command.

The unquoted $1 parameter can cause commitlint to fail if the file path contains spaces or special characters.

🔎 Proposed fix
 # commitlint 실행
-if npx --no -- commitlint --edit $1; then
+if npx --no -- commitlint --edit "$1"; then
   echo "✅ 커밋 메시지가 규칙에 맞습니다."
   exit 0
 else
📝 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
if npx --no -- commitlint --edit $1; then
if npx --no -- commitlint --edit "$1"; then
echo "✅ 커밋 메시지가 규칙에 맞습니다."
exit 0
else
🤖 Prompt for AI Agents
In @.husky/commit-msg around line 15, The commitlint invocation uses an unquoted
parameter $1 which can break when the commit message file path contains spaces
or special characters; update the command in the .husky/commit-msg hook that
calls commitlint (the line starting with "if npx --no -- commitlint --edit $1;
then") to quote the parameter (use "$1") so the path is passed as a single
argument to commitlint.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @.coderabbit.yaml:
- Around line 14-16: Remove the duplicate YAML key by keeping only one
definition of high_level_summary_placeholder; either delete the later occurrence
(the simpler default at line 24) to retain your custom Korean multi-line
placeholder (the block starting with "@coderabbitai summary"), or replace the
first multi-line block with the single-line default — ensure only one
high_level_summary_placeholder entry remains in the file.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11263f0 and 204867d.

📒 Files selected for processing (1)
  • .coderabbit.yaml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:00:01.926Z
Learning: This project uses svgr for automatic SVG to React component conversion. Running `npm run svgr` automatically converts all svgr files to React component format and handles camelCase conversion for SVG attributes (e.g., stroke-width → strokeWidth).
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:10-10
Timestamp: 2025-07-13T00:27:31.464Z
Learning: Using TypeScript interfaces for React component props (like StudentHeaderProps) provides clear structure, improves readability, and makes components more maintainable and extensible for future development.
Learnt from: suminb99
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/assets/svg/ChatIcon.tsx:14-14
Timestamp: 2025-07-16T13:14:38.834Z
Learning: In this project, the svgr workflow requires placing original SVG files in the `public/svg` folder first, then running `npm run svgr` command to generate converted TSX files in the `src/assets/svg` folder according to the root configuration.
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 6
File: src/App.tsx:6-11
Timestamp: 2025-07-16T12:33:43.867Z
Learning: JiiminHa prefers hierarchical routing structure with role-based path organization: common routes at root level (/), student-specific routes under /student prefix, and admin-specific routes under /admin prefix, using nested routes with a shared Layout component for consistent UI patterns.
Learnt from: JiiminHa
Repo: 2025-snowCode/snowCode-Client PR: 2
File: src/components/Header/StudentHeader.tsx:6-18
Timestamp: 2025-07-13T00:25:00.538Z
Learning: User JiiminHa prefers using semantic HTML tags over excessive div usage for better code structure and accessibility in React components.
🪛 YAMLlint (1.37.1)
.coderabbit.yaml

[error] 24-24: duplication of key "high_level_summary_placeholder" in mapping

(key-duplicates)

🔇 Additional comments (1)
.coderabbit.yaml (1)

10-115: Configuration aligns well with project standards.

The path-specific review instructions are comprehensive and well-aligned with the learnings retrieved from prior PRs. Korean-language tone instructions, hierarchical component/hook/TypeScript conventions, and auto-review settings with appropriate base branches and tool integrations are clearly defined.

Comment on lines +14 to +16
high_level_summary_placeholder: |
@coderabbitai summary
(졸업작품 평가 기준: 구조 / 타입 안정성 / 접근성 관점 요약)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix duplicate YAML key high_level_summary_placeholder.

The configuration defines high_level_summary_placeholder twice (lines 14-16 and line 24), which is invalid YAML and will cause a parsing error. The schema allows only one definition per key.

Line 24 appears to be a duplicate of the schema default. Remove it to retain your custom Korean-language placeholder (lines 14-16), or replace lines 14-16 with the simpler line 24 value if the customization is unintended.

🔎 Proposed fix: Remove line 24
  abort_on_close: true
- high_level_summary_placeholder: '@coderabbitai summary'
  collapse_walkthrough: true

Also applies to: 24-24

🤖 Prompt for AI Agents
In @.coderabbit.yaml around lines 14 - 16, Remove the duplicate YAML key by
keeping only one definition of high_level_summary_placeholder; either delete the
later occurrence (the simpler default at line 24) to retain your custom Korean
multi-line placeholder (the block starting with "@coderabbitai summary"), or
replace the first multi-line block with the single-line default — ensure only
one high_level_summary_placeholder entry remains in the file.

@suminb99
Copy link
Contributor

?react를 붙이면 SVG를 import 시점에 컴포넌트로 변환할 수 있어서 새 아이콘 추가할 때마다 npm run svgr로 사전 변환할 필요가 없네요! 변환 산출물(tsx)이 쌓이는 문제도 줄어서 에셋 관리가 더 깔끔해진 것 같습니다.

@suminb99
Copy link
Contributor

PR 확인했습니다! 수고하셨어요 👍

@suminb99
Copy link
Contributor

@JiiminHa PR 머지 부탁드려요!

@suminb99 suminb99 merged commit 05d4731 into develop Jan 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧹 chore 프로젝트 설정 / 빌드 / 패키지 관리

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: 에셋 관리 구조 개선 및 라우팅 최적화 (Prettier 도입)

3 participants