Skip to content

Conversation

@LeeCh0129
Copy link

@LeeCh0129 LeeCh0129 commented Jun 13, 2025

📌 변경 사항 개요

사이드바에 대시보드 생성 모달 기능을 구현하였고, API 연동까지 완료했습니다.

✨ 요약

  • Zustand 기반 모달 상태 관리 스토어 구현
  • 대시보드 생성 모달 UI 구현
  • POST /dashboards API 연동
  • 대시보드 생성 후 해당 페이지로 이동

📝 상세 내용

1. 모달 상태관리(useModalSotre.ts)

  • Zustand를 이용해 모달 상태 관리
  • createDashbaordModalOpen 상태와 열기/닫기 액션

2. 타입 정의(dashboard.ts)

  • CreateDashboardRequest 타입 추가(title, color 필드)
  • ModalState 인터페이스 추가

3. 사이드바 컴포넌트 업데이트(Sidebar.tsx)

  • useMdoalStore 훅 연동으로 모달 열기

4. 대시보드 생성 모달(CreateDashboardModal.tsx)

  • 대시보드 생성 모달 UI
  • 폼 처리
  • 색상 선택(5가지 프리셋 색상 중 선택 가능, check.svg 아이콘으로 선택 상태 표시)
  • POST /dashbaords API 연동
  • 대시보드 생성 성공 시 /dashboard/{id}로 이동
  • 모달 외부 클릭 시 닫기, 대시보드 이름 미입력 시 생성 버튼 비활성화

🔗 관련 이슈

#49

🖼️ 스크린샷

image
image
image

✅ 체크리스트

  • 브랜치 네이밍 컨벤션을 준수했습니다
  • 커밋 컨벤션을 준수했습니다
  • 코드가 프로젝트의 스타일 가이드라인을 준수합니다

💡 참고 사항

  • 테스트용 토큰을 수동 설정하여 개발 진행
  • API 테스트는 스웨거를 통해 발급받은 토큰으로 검증 완료
  • 이후 사이드바 목데이터를 실제 API 연도응로 변경 예정

Summary by CodeRabbit

  • 신규 기능

    • 대시보드 생성을 위한 모달이 추가되어, 사이드바 및 테스트 페이지에서 대시보드 생성 버튼 클릭 시 모달이 열립니다.
    • 대시보드 이름 입력, 색상 선택, 생성 및 취소가 가능하며, 입력값이 없거나 생성 중에는 생성 버튼이 비활성화됩니다.
  • 스타일

    • 새로운 배경색 유틸리티 클래스(.BG-violet)가 추가되었습니다.

@LeeCh0129 LeeCh0129 added this to the 1차 구현 기간 milestone Jun 13, 2025
@LeeCh0129 LeeCh0129 self-assigned this Jun 13, 2025
@LeeCh0129 LeeCh0129 added the ✨Feat 기능 개발 label Jun 13, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 13, 2025

"""

Walkthrough

대시보드 생성 모달 기능이 추가되었습니다. Zustand를 활용한 모달 상태 관리, 대시보드 생성 API 연동, 컬러 선택 기능이 구현되었으며, 사이드바 및 테스트 페이지에서 모달을 열 수 있도록 통합되었습니다. 새로운 CSS 유틸리티 클래스도 추가되었습니다.

Changes

파일/경로 변경 요약
src/app/globals.css .BG-violet 배경색 유틸리티 클래스 추가
src/app/shared/components/common/sidebar/Sidebar.tsx 모달 스토어 연동, 대시보드 생성 버튼이 실제 모달 오픈 함수 호출하도록 변경
src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx 대시보드 생성 모달 컴포넌트 신규 추가
src/app/shared/lib/axios.ts import 순서 변경 (기능 변화 없음)
src/app/shared/store/useModalStore.ts Zustand 기반 모달 상태 관리 훅 및 open/close 함수 추가
src/app/shared/types/dashboard.ts 모달 상태 및 제어 함수 포함하는 ModalState 인터페이스 추가
src/app/tester/page.tsx 클라이언트 컴포넌트로 전환, 모달 버튼 및 CreateDashboardModal 컴포넌트 통합

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Sidebar
    participant useModalStore
    participant CreateDashboardModal
    participant API
    participant Router

    User->>Sidebar: "대시보드 생성" 버튼 클릭
    Sidebar->>useModalStore: openCreateDashboardModal()
    useModalStore-->>CreateDashboardModal: createDashboardModalOpen = true
    User->>CreateDashboardModal: 폼 입력 및 색상 선택
    User->>CreateDashboardModal: "생성" 버튼 클릭
    CreateDashboardModal->>API: POST /dashboard (title, color)
    API-->>CreateDashboardModal: 생성된 대시보드 정보 반환
    CreateDashboardModal->>Router: 상세 페이지로 이동
    CreateDashboardModal->>useModalStore: closeCreateDashboardModal()
Loading

Possibly related issues

  • coplan#49: Zustand 상태관리, 모달 컴포넌트, API 연동, 사이드바 버튼 동작 등 대시보드 생성 모달 구현 요구사항과 정확히 일치합니다.

Possibly related PRs

  • coplan#42: Sidebar 컴포넌트 확장 및 대시보드 생성 모달 통합 관련, Sidebar UI 및 네비게이션 초안 PR과 컴포넌트 레벨에서 연관이 있습니다.

Suggested reviewers

  • LeeCh0129
  • yuj2n

Poem

토끼가 깡총, 모달을 열었네
대시보드 만들기, 색상도 곱게
Sidebar에서 클릭!
Zustand로 똑딱!
새로운 공간, 신나게 hop hop!
🎨🐇
"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-15T17_58_05_759Z-debug-0.log


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between add715f and 2dbfac5.

📒 Files selected for processing (1)
  • src/app/globals.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/globals.css

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • 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

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (9)
src/app/globals.css (1)

25-27: .BG-violet 유틸리티의 변형(hover‧dark) 누락
다른 색상 유틸(예: .BG-blue)과 달리 hover·dark 변형이 없어 UI 일관성이 깨질 수 있습니다.

-.BG-violet {
-  @apply bg-[#228DFF];
-}
+.BG-violet {
+  @apply bg-[#228DFF] hover:bg-[#2172C9] dark:bg-[#228DFF] dark:hover:bg-[#2172C9];
+}
src/app/shared/types/dashboard.ts (1)

35-41: 도메인 타입 파일에 UI 상태 타입이 혼재됨
ModalState 는 모달 UI 전용 상태로 도메인 모델과 무관합니다.
스토어 정의 파일(useModalStore.ts) 혹은 별도 uiStates.ts 로 분리하면 타입 레이어가 깔끔해집니다.

src/app/shared/components/common/sidebar/Sidebar.tsx (1)

7-16: handleCreateDashboard 중간 래퍼 함수 불필요
openCreateDashboardModal 을 그대로 전달하면 불필요한 함수 생성이 사라져 재렌더 횟수를 줄일 수 있습니다.

-import { useModalStore } from '@/app/shared/store/useModalStore'
+import { useModalStore } from '@/app/shared/store/useModalStore'

 ...
-  const { openCreateDashboardModal } = useModalStore()
+  const { openCreateDashboardModal } = useModalStore()

 ...
-  const handleCreateDashboard = () => {
-    openCreateDashboardModal()
-  }

그리고 아래 JSX:

-<CreateDashboardButton onClick={handleCreateDashboard} />
+<CreateDashboardButton onClick={openCreateDashboardModal} />
src/app/tester/page.tsx (1)

8-10: 상대경로 대신 alias 사용 권장
프로젝트 전역에서 alias(@/app/...)를 사용하고 있으므로 통일성을 위해 해당 import도 alias로 바꾸면 가독성이 좋아집니다.

-import CreateDashboardModal from '../shared/components/common/sidebar/modal/CreateDashboardModal'
-import { useModalStore } from '../shared/store/useModalStore'
+import CreateDashboardModal from '@/app/shared/components/common/sidebar/modal/CreateDashboardModal'
+import { useModalStore } from '@/app/shared/store/useModalStore'
src/app/shared/store/useModalStore.ts (1)

3-3: 경로 표현 방식 통일 제안
다른 파일들(CreateDashboardModal.tsx 등)은 @/app/shared/... 절대 경로 alias를 사용하고 있는데, 이곳만 상대 경로(../types/dashboard)를 사용하고 있습니다. 경로 스타일을 통일하면 리팩터링 시 유지보수가 수월합니다.

-import { ModalState } from '../types/dashboard'
+import { ModalState } from '@/app/shared/types/dashboard'
src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (4)

15-17: Zustand selector + shallow 비교로 불필요한 리렌더링 최소화
스토어에서 필요한 두 값만 선택해도, selector 없이 전체 스토어를 구독하면 다른 modal 관련 상태가 추가될 때마다 모달 컴포넌트가 리렌더링됩니다. selector + shallow를 사용해 의도치 않은 렌더링을 막을 수 있습니다.

-import { useModalStore } from '@/app/shared/store/useModalStore'
+import { useModalStore } from '@/app/shared/store/useModalStore'
+import { shallow } from 'zustand/shallow'

-const { createDashboardModalOpen, closeCreateDashboardModal } =
-  useModalStore()
+const { createDashboardModalOpen, closeCreateDashboardModal } =
+  useModalStore(
+    (state) => ({
+      createDashboardModalOpen: state.createDashboardModalOpen,
+      closeCreateDashboardModal: state.closeCreateDashboardModal,
+    }),
+    shallow,
+  )

45-47: 에러 처리 향상
현재는 콘솔 로그만 남기고 사용자에게 아무 피드백이 없습니다. 토스트/알림 컴포넌트를 통해 실패 이유를 안내해 주세요. 예: 네트워크 오류, 중복 이름 등.

-} catch (error) {
-  console.error('대시보드 생성 오류:', error)
+} catch (error) {
+  console.error('대시보드 생성 오류:', error)
+  // TODO: 토스트 라이브러리로 사용자에게 에러 메시지 표시
}

76-78: 접근성(Accessibility) 속성 추가 권장
모달 백드롭에 role="dialog"·aria-modal="true"·aria-labelledby 등을 지정하면 스크린 리더 사용자가 현재 포커스가 모달임을 인지할 수 있습니다.

-<div
-  className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
-  onClick={handleBackdropClick}
->
+<div
+  role="dialog"
+  aria-modal="true"
+  aria-labelledby="create-dashboard-title"
+  className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
+  onClick={handleBackdropClick}
+>

114-122: 체크 아이콘 컨테이너에 flex 클래스 누락
items-center justify-center만으로는 정렬이 적용되지 않습니다. flex를 추가해 정확히 중앙에 배치하세요.

-<div className="relative size-24 items-center justify-center">
+<div className="relative size-24 flex items-center justify-center">
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc76955 and 87c31a4.

⛔ Files ignored due to path filters (1)
  • public/images/check.svg is excluded by !**/*.svg
📒 Files selected for processing (7)
  • src/app/globals.css (1 hunks)
  • src/app/shared/components/common/sidebar/Sidebar.tsx (2 hunks)
  • src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (1 hunks)
  • src/app/shared/lib/axios.ts (1 hunks)
  • src/app/shared/store/useModalStore.ts (1 hunks)
  • src/app/shared/types/dashboard.ts (1 hunks)
  • src/app/tester/page.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/app/tester/page.tsx (2)
src/app/shared/store/useModalStore.ts (1)
  • useModalStore (5-14)
src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (1)
  • CreateDashboardModal (13-154)
src/app/shared/components/common/sidebar/Sidebar.tsx (1)
src/app/shared/store/useModalStore.ts (1)
  • useModalStore (5-14)
src/app/shared/store/useModalStore.ts (1)
src/app/shared/types/dashboard.ts (1)
  • ModalState (37-41)
src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (2)
src/app/shared/store/useModalStore.ts (1)
  • useModalStore (5-14)
src/app/shared/types/dashboard.ts (1)
  • CreateDashboardRequest (31-34)
🔇 Additional comments (2)
src/app/shared/lib/axios.ts (1)

2-4: 기능 영향 없는 import 순서 변경, OK
실제 로직에는 변화가 없으며 사이드 이펙트도 없습니다. 그대로 두셔도 무방합니다.

src/app/shared/store/useModalStore.ts (1)

5-14: Zustand 스토어 구현은 명확하며 기능적으로 문제 없습니다.
현재 요구사항을 충족하며 타입도 올바르게 지정돼 있습니다. 👍

@LeeCh0129 LeeCh0129 linked an issue Jun 13, 2025 that may be closed by this pull request
4 tasks
Copy link
Contributor

@dkslel1225 dkslel1225 left a comment

Choose a reason for hiding this comment

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

모달 구현 수고하셨습니다!
모달 open/close 상태를 Zustand로 전역 관리하셨는데,
useState가 아닌, Zustand를 사용하신 이유가 궁금합니당


// 모달 외부 클릭 시 닫기
const handleBackdropClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) {
Copy link
Contributor

Choose a reason for hiding this comment

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

e.target이랑 e.currentTarget이 각각 뭘 가리키고 있는건가요?

Copy link
Author

Choose a reason for hiding this comment

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

Zustand를 사용한 이유는 모달 관련 로직을 한곳에서 관리하기 쉽다고 생각했고, 추후에 다른 모달(컬럼 모달)도 비슷한 패턴으로 추가하기 쉽다고 판단해서 사용했습니다.

현재 구조에서 SidebarCreateDashboardModal이 각각 독립적으로 useModalStore를 사용해서 상태를 공유하고 있는데, 이렇게 이용하면 컴포넌트 간 결합도를 낮출 수 있기 때문입니다. 만약 useState를 사용했다면 상위 컴포넌트에서 모달 상태를 관리하고 props로 전달해서 사용했었어야 했습니다.

e.target은 실제로 클릭된 요소(이벤트가 발생한 요소)이고,
e.currentTarget은 이벤트 리스너가 등록된 요소(해당 코드에서는 모달 백드롭 div)를 가리킵니다.

모달 외부/배경 클릭 시 e.target === e.currentTarget (백드롭 자체 클릭) -> 모달이 닫힘.
모달 내부 클릭 시 e.target !== e.currentTarget (자식 요소 클릭, 이벤트 버블링) -> 모달 유지

이 방식으로 모달 외부 클릭 시에만 모달을 닫고, 모달 내부 클릭 시에는 닫히지 않도록 구현했습니다.

Copy link
Contributor

@yuj2n yuj2n left a comment

Choose a reason for hiding this comment

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

찬호님 모달 구현 수고 많으셨습니당~!!

Comment on lines +1 to +14
import { create } from 'zustand'

import { ModalState } from '../types/dashboard'

export const useModalStore = create<ModalState>((set) => ({
// 초기 상태
createDashboardModalOpen: false,

// 모달 열기
openCreateDashboardModal: () => set({ createDashboardModalOpen: true }),

// 모달 닫기
closeCreateDashboardModal: () => set({ createDashboardModalOpen: false }),
}))
Copy link
Contributor

Choose a reason for hiding this comment

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

Zustand로 모달 상태 관리 해주셨군용!!
참고해서 공통 모달 컴포넌트 작성해보도록 하겠습니다~

Copy link

@Insung-Jo Insung-Jo left a comment

Choose a reason for hiding this comment

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

생성 모달 구현 수고 많으셨습니다!! 저도 글로벌 스타일에 새로 작성한 게 있어서 충돌이 일어났었는데 그 부분은 해결 했습니다~

@LeeCh0129 LeeCh0129 merged commit f210b1c into develop Jun 15, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨Feat 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Feat: 사이드바 대시보드 생성 모달 구현

5 participants