Skip to content

Conversation

@dkslel1225
Copy link
Contributor

@dkslel1225 dkslel1225 commented Jun 16, 2025

📌 변경 사항 개요

  • Feat: 대시보드 상세 페이지 - 터치 기반 드래그 앤 드롭
    • 터치와 스크롤 구분하기 위해 isLongPress 체크
    • 드래그중인 카드가 위치한 컬럼을 표시(배경 색상을 변경하여 구분 가능)
    • 남은 개선점:
      • requestAnimationFrame 적용.
      • 드래그 중 기본 스크롤은 막되, 클론 요소가 화면 상단/하단 근처로 이동하면 자동으로 스크롤되도록 구현
  • 🎨 style: 대시보드 상세 페이지 스타일 작업
    • Avatar내부의 getColors 함수를 공통 함수로 분리함
    • tailwind.config.ts - 반응형 커스텀
  • 뮤테이션 함수 개선(useCardMutation.ts) & draggingCard에서 columnId 제거 (useDragStore.ts)

✨ 요약

📝 상세 내용

터치 기반 드래그 앤 드롭

  • 터치이벤트는 전부 page.tsx에 있습니다.

    1. 드래그 시작: touchstart 이벤트

    • touchstart 발생 시:
      • 첫 터치 위치(touches[0].clientX, clientY) 저장
      • 어떤 카드가 터치되었는지 식별 (ID로 찾음: ‘data-card-cata’)
      • 해당 카드 데이터를 드래깅 전역 상태에 저장 (setDraggingCard() - zustand 사용)
      • 복제 요소를 생성함 (cloneNode)

    2. 드래그 중: touchmove 이벤트

    • touchmove 시:
      • 터치 좌표 계속 추적
      • 드래깅 중인 요소를 해당 좌표로 따라가도록 위치 업데이트
      • 현재 어느 컬럼 위에 드래그 중인지 확인
      • 현재 위치의 컬럼의 스타일 변형

    4. 드래그 종료: touchend 이벤트

    • touchend 발생 시:
      • 드래그 중인 카드 있는지 재확인
      • 클론 카드 제거
      • 어떤 컬럼에 드롭했는지 - 현재 위치의 컬럼 가져옴
      • 타겟 컬럼으로 카드데이터 이동 (useCardMutation.ts - 서버, 캐시 업데이트)
        이 외, 상세 코드에 질문 남겨주시면 답변 드리겠습니다

🎨 tailwind.config.ts - 반응형 커스텀

mobile,tablet,desktop, 설정해뒀습니다.
"사이즈: 스타일" 이렇게 작성하시면 반응형 스타일 적용됩니다.

        className="tablet:flex-col flex" // 타블렛 사이즈부터, flex-col 적용

🔗 관련 이슈

🖼️ 스크린샷

2025-06-16.3.32.07.mov

✅ 체크리스트

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

💡 참고 사항

Summary by CodeRabbit

  • 신규 기능

    • 로그인 및 회원가입 폼, 인증 로고, 입력 컴포넌트 등 인증 관련 UI 추가
    • 대시보드용 사이드바, 대시보드 아이템, 대시보드 생성 버튼 컴포넌트 추가
    • 사용자 아바타, 유저 정보, 협업자 리스트 및 툴팁 컴포넌트 도입
    • 드롭다운, 드래그 앤 드롭, 카드 이동 등 대시보드 상호작용 기능 추가
    • 카드, 담당자 등 데이터 타입 및 유틸리티 함수 다수 추가
  • 개선 사항

    • 카드 및 컬럼에 드래그 앤 드롭 기능과 터치 기반 이동 지원
    • 태그 색상 동적 적용, 헤더/레이아웃 구조 개선, 글로벌 스타일 유틸리티 클래스 추가
    • 반응형 브레이크포인트 및 타입스크립트 경로 별칭 추가
  • 버그 수정

    • 인증 로그아웃 시 저장된 인증 정보 완전 삭제 처리
  • 테스트 및 문서

    • 테스트용 페이지 레이아웃 개선 및 구조화
  • CI/CD 및 설정

    • ESLint 자동 검사 CI 워크플로우 추가
    • Tailwind, tsconfig 등 프로젝트 설정 확장

jyn added 9 commits June 14, 2025 16:52
- useDragStore에서 cardId + columnId 대신 Card 객체 + columnId 저장
- extractedCard 로직 제거로 mutation 함수 단순화
- 드래그 작업에서 타입 안전성 향상 및 복잡도 감소
♻️ refactor: draggingCard에서 columnId 제거 (useDragStore.ts)
—> 카드 전체 데이터 하나로 해결함(“cardData: Card”)
 🎨 style: 페이지 스타일 작업 중
✨ feat: Avatar내부의 getColors 함수를 공통 함수로 분리함
🐛 fix: 드래그중인 카드가 없어도 컬럼의 배경색이 변함-->draggingCard체크 조건 추가
@coderabbitai
Copy link

coderabbitai bot commented Jun 16, 2025

Walkthrough

이번 변경에서는 유틸리티 함수, 스타일, 그리고 드래그 앤 드롭 기능이 대대적으로 추가 및 개선되었습니다.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Card
  participant Column
  participant useDragStore
  participant useCardMutation
  participant API

  User->>Card: 드래그 시작 (onDragStart/touch)
  Card->>useDragStore: setDraggingCard(card)
  User->>Column: 카드 드롭 (onDrop/touchEnd)
  Column->>useDragStore: draggingCard 조회
  alt 컬럼 변경 필요 시
    Column->>useCardMutation: mutate({ cardId, fromColumnId, toColumnId })
    useCardMutation->>API: updateCardColumn(cardId, toColumnId)
    useCardMutation->>useDragStore: clearDraggingCard()
  else 동일 컬럼
    Column->>useDragStore: clearDraggingCard()
  end
Loading

Possibly related PRs

  • CoPlay-FE/coplan#48: 대시보드 카드 드래그 앤 드롭, 관련 스토어, API, 뮤테이션 훅 등 동일 파일 및 기능 확장
  • CoPlay-FE/coplan#42: 사이드바 및 관련 컴포넌트, 타입 추가 등 동일 파일 및 기능 구현
  • CoPlay-FE/coplan#36: 동일한 CI 워크플로우 파일(.github/workflows/ci.yml) 추가
🔧 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-16T06_40_36_734Z-debug-0.log

✨ Finishing Touches
  • 📝 Docstrings were successfully generated. (🔄 Check again to generate docstrings again)

🪧 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.

@dkslel1225 dkslel1225 self-assigned this Jun 16, 2025
@dkslel1225 dkslel1225 added ✨Feat 기능 개발 🎨Style UI, 스타일 관련 수정 🔧Chore 설정, 빌드 변경 labels Jun 16, 2025
@dkslel1225 dkslel1225 added this to the 2차 구현 기간 milestone Jun 16, 2025
@dkslel1225 dkslel1225 linked an issue Jun 16, 2025 that may be closed by this pull request
1 task
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: 20

🧹 Nitpick comments (32)
src/app/shared/lib/getColor.ts (2)

1-5: 의도는 색상 ‘인덱스’ 반환이므로 함수명 혼동 가능
getColor 라는 이름은 문자열 hex 값을 돌려줄 것처럼 보이지만 실제로는 배열 인덱스를 반환합니다.

-export function getColor(text: string, customColors: string[]): number {
+export function getColorIndex(text: string, palette: string[]): number {

이후 호출부에서 palette[getColorIndex(tag, palette)] 형태로 쓰면 의미가 더 명확해집니다.


1-5: 단순 합 해시 → 아나그램 충돌 위험
abccba 가 동일 인덱스를 갖게 됩니다. UX 상 큰 문제는 아니지만, 충돌을 줄이고 싶다면 DJB2 같은 경량 해시를 쓰거나 hash = ((acc << 5) - acc) + charCode 패턴을 고려해 보세요.

.github/workflows/ci.yml (1)

11-12: self-hosted 러너 사용 시 실패 대체 경로 필요
사내 러너 장애 시 워크플로 전체가 멈춥니다.

runs-on: [self-hosted, ubuntu-latest]

처럼 fallback 러너를 지정하거나, runner-group을 활용해 가용성을 확보해 주세요.

src/app/globals.css (1)

69-71: 드래그 Hover 색상에 다크 모드 변형을 함께 정의해 주세요.

.BG-drag-hovered 클래스는 라이트 모드 전용 색상(bg-blue-100)만 적용돼 있어 다크 모드에서 시각 피드백이 사라집니다. 다른 유틸리티처럼 dark:bg-[#2C3641] 등을 추가해 두 테마 모두 일관된 UX를 보장해 주세요.

src/app/shared/components/common/header/Collaborator/Tooltip.tsx (3)

20-30: 스크롤/리사이즈 시 위치 재계산 누락

툴팁은 visible 발생 시 한 번만 좌표를 계산합니다. 창 크기 변경, 스크롤 이동 후에도 툴팁이 그대로 남아 위치가 어긋날 수 있으므로 window.scroll, resize 이벤트에 대응해 좌표를 갱신하거나 IntersectionObserver/ResizeObserver를 고려해 주세요.


40-48: 다크 모드 색상 하드코딩

배경·글자색을 직접 HEX로 지정해 다크 모드 전환 시 일관성을 잃습니다. Tailwind 클래스(BG-white, Text-black 등)나 CSS 변수 사용으로 테마 의존성을 제거하는 편이 유지보수에 유리합니다.


60-68: 불필요한 래퍼 제거로 DOM 최적화 가능

<div className="relative flex items-center">는 자식이 하나뿐인 경우가 대부분이므로, 필요 없으면 Fragment로 대체해 DOM 깊이를 줄일 수 있습니다.

src/app/(auth)/login/page.tsx (1)

5-10: 불필요한 Fragment 제거

단일 자식만 반환하므로 빈 Fragment(<> </>)가 필요 없습니다. 간단히 <LoginForm />를 반환하도록 수정해 가독성을 높여 주세요.

-  return (
-    <>
-      <LoginForm />
-    </>
-  )
+  return <LoginForm />
src/app/shared/lib/cn.ts (1)

4-6: clsx 인수 전달 방식 개선 제안

clsx 는 가변 인자를 받도록 설계되어 있어 clsx(...inputs) 로 전달하는 편이 타입 추론과 가독성 모두에서 일반적입니다. 현재처럼 배열 하나를 넘겨도 동작은 하지만 타입 경고가 발생하거나 중첩 배열이 만들어질 수 있습니다.

-export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs))
+export function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(...inputs))
 }
src/app/shared/components/common/UserInfo.tsx (1)

11-18: 접근성 & 재사용성을 위한 forwardRef 적용 고려

외부에서 UserInfo 요소에 직접 포커스·스크롤 제어가 필요한 경우가 잦습니다(예: 메뉴 트리거). forwardRef 를 적용해 DOM 참조를 노출하면 컴포넌트 활용도가 높아집니다. 한편, span 대신 p/div 등 블록 요소가 필요할 때도 유연하게 대응할 수 있습니다.
간단히 아래와 같이 개선 가능합니다.

-import { Avatar } from './Avatar'
+import { forwardRef } from 'react'
+import { Avatar } from './Avatar'
 ...
-export function UserInfo({ nickname, imageUrl, size = 36 }: UserInfoProps) {
-  return (
+export const UserInfo = forwardRef<HTMLDivElement, UserInfoProps>(
+  ({ nickname, imageUrl, size = 36 }, ref) => (
     <div ref={ref} className="flex items-center gap-4">
       <Avatar nickname={nickname} imageUrl={imageUrl} size={size} />
       <span className="text-sm font-semibold">{nickname}</span>
     </div>
-  )
-}
+  ),
+)
src/app/shared/components/common/header/UserDropdown.tsx (1)

20-28: width="w-6" 값이 Dropdown 내부 스타일과 맞지 않을 가능성

w-6(24 px) 은 메뉴 아이템(텍스트 포함)에 비해 지나치게 좁아 클릭 영역이 잘리거나 overflow 가 발생할 수 있습니다. 사용 의도를 재확인하고 w-48 등 충분한 가로폭을 지정해 주세요.

src/app/features/auth/schemas/loginValidation.ts (1)

1-16: 패스워드 복잡도 규칙 추가 고려

현행 검증은 길이만 확인합니다. 서비스 정책에 따라 대·소문자, 숫자, 특수문자 포함 여부 등을 추가하면 보안 수준을 높일 수 있습니다. 필요 시 정규식 패턴과 맞춤 메시지를 포함해 주세요.

src/app/dashboard/[id]/Card/Tags.tsx (1)

6-7: 컬러 배열은 컴포넌트 외부로 이동해 재-렌더시 재생성을 방지하세요
bgColorstextColors를 함수 내부에 선언하면 렌더링마다 새 배열이 생성됩니다. 불필요한 메모리 할당을 줄이려면 파일 상단(모듈 스코프)으로 옮기는 편이 좋습니다.

-  const bgColors = ['#F9EEE3', '#E7F7DB', '#F7DBF0', '#DBE6F7']
-  const textColors = ['#D58D49', '#86D549', '#D549B6', '#4981D5']
+const BG_COLORS = ['#F9EEE3', '#E7F7DB', '#F7DBF0', '#DBE6F7'] as const
+const TEXT_COLORS = ['#D58D49', '#86D549', '#D549B6', '#4981D5'] as const
+
+export default function Tags({ tags }: { tags: string[] }) {
src/app/features/auth/hooks/useLoginSubmit.ts (1)

17-24: 에러 메시지 타입이 불확실할 때 안전한 디폴트 추가 권장
Axios 응답 message가 문자열이 아닐 가능성을 대비해 typeof message === 'string' 체크 후 사용하면 토스트 출력 오류를 방지할 수 있습니다.

-        const message = e.response?.data?.message
-        toast.error(message ?? '로그인 실패')
+        const message = e.response?.data?.message
+        toast.error(
+          typeof message === 'string' && message.length > 0
+            ? message
+            : '로그인 실패',
+        )
src/app/dashboard/[id]/store/useDragStore.ts (2)

4-7: 타입 명명 규칙 통일 필요

interface draggingCard 와 같이 소문자로 시작하는 타입은 팀 컨벤션(PascalCase)을 벗어납니다. DraggingCard 로 수정하거나 아예 별도 타입 없이 Card 자체를 직접 사용해도 충분합니다.

-interface draggingCard {
+interface DraggingCard {
   cardData: Card
 }

10-11: 파라미터 타입 중복 정의

setDraggingCard 의 인자 타입을 { cardData: Card } 로 직접 지정하기보다는 바로 위에서 정의한 DraggingCard(또는 동일 구조)를 재사용하면 타입 중복을 줄일 수 있습니다.

- setDraggingCard: (data: { cardData: Card }) => void
+ setDraggingCard: (data: DraggingCard) => void
src/app/features/auth/components/LoginForm.tsx (2)

41-44: autoComplete 속성 값 재검토

비밀번호 입력의 autoComplete="off" 는 일부 브라우저에서 무시되며 UX 를 떨어뜨릴 수 있습니다. 일반적으로 로그인 폼에는 autoComplete="current-password" 를 권장합니다.

- autoComplete="off"
+ autoComplete="current-password"

51-55: 비활성 상태 스타일 Tailwind 내장 variant 활용

disabled: variant를 사용하면 조건부 클래스를 줄일 수 있습니다.

- isValid && !isSubmitting ? 'BG-blue' : 'BG-blue-disabled',
+ 'BG-blue disabled:BG-blue-disabled',

이를 통해 로직 복잡도를 낮추고 스타일 일관성을 유지할 수 있습니다.

src/app/(auth)/signin/page.tsx (1)

57-57: 임시 입력 필드 및 페이지 정리 필요

<Input labelName="안녕" name="text" /> 는 실제 로그인·회원가입 흐름과 무관한 임시 코드로 보입니다. 기능 구현이 끝났다면 제거하거나 스토리북/샘플 컴포넌트로 분리해 주세요.

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

14-61: 목데이터 정의 위치 및 재생성 비용

mockDashboards 가 컴포넌트 내부에 있어 렌더링마다 새 배열이 생성됩니다. 실제 API 연동 전이라도 상수는 컴포넌트 외부로 이동하거나 useMemo 로 래핑해 불필요한 재렌더링을 방지하는 편이 좋습니다.


63-66: 라우팅 시 에러 방지

router.push 호출 시 현재 경로와 동일하면 불필요한 네비게이션이 발생합니다. 클릭한 대시보드가 이미 활성화되어 있을 때는 early-return 하도록 검토해 주세요.

if (pathname !== `/dashboard/${dashboardId}`) {
  router.push(`/dashboard/${dashboardId}`)
}
src/app/shared/components/common/sidebar/DashboardItem.tsx (1)

36-43: 이미지 로딩 상태 처리 고려

왕관 이미지에 로딩 상태나 에러 처리를 추가하면 사용자 경험이 향상될 수 있습니다.

src/app/dashboard/[id]/page.tsx (1)

32-32: 사용하지 않는 주석 코드 제거

주석 처리된 코드는 제거하는 것이 좋습니다.

-    // setDraggingCard({ cardData: cardData }) // 전역상태에, 현재 드래그할 카드 저장(후에 뮤테이션 함수에 전달해서 캐시 업데이트에 사용)
src/app/shared/types/dashboard.ts (1)

2-10: 날짜 필드에 string 대신 Date 사용 고려
createdAt, updatedAt 필드를 문자열로 두면 소비 측에서 매번 파싱 로직을 가져가야 합니다. API 스펙을 조정할 수 있다면 Date 타입(ISO-8601 문자열을 받아서 즉시 파싱)으로 정의하거나, 최소한 별도의 type Timestamp = string alias로 명시해 두면 의도가 더 분명해집니다.

src/app/shared/components/common/Avatar.tsx (1)

13-23: customColors 분리 제안
customColors 상수가 컴포넌트 내부에 정의돼 있어, 다른 곳에서 같은 팔레트를 써야 할 때 중복 선언될 가능성이 있습니다. shared/constants/colors.ts 같은 파일로 이동해 재사용성을 높여 주세요.

src/app/dashboard/[id]/Card/Card.tsx (2)

20-24: HTML data-attribute에 대용량 JSON 직렬화 주의
data-card-dataJSON.stringify(card)를 그대로 넣으면 DOM 노드에 불필요하게 큰 문자열이 삽입됩니다. DnD 로직에서 꼭 필요하다면 id만 두고, 상세 데이터는 Zustand나 context에서 조회하는 쪽이 메모리·성능 모두 유리합니다.


20-23: draggable 속성은 boolean 리터럴 사용
React에서는 문자열 "true" 대신 draggable={true}를 권장합니다.

src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx (1)

49-56: “+N” 툴팁 내용 부정확 가능성
visibleCollaborators[0].nickname 은 이미 화면에 표시된 사람입니다. 초과 인원을 설명하려면 collaborators[MAX_VISIBLE].nickname 등, 실제로 숨겨진 첫 번째 사용자를 참조하는 편이 직관적입니다.

src/app/shared/components/Input.tsx (1)

41-68: 접근성 속성 추가
에러 메시지가 있을 때 aria-describedby를 입력 요소에 연결하면 스크린리더가 오류를 읽어줄 수 있습니다. 또한 비밀번호 토글 버튼에 aria-label을 제공해 주세요.

-  {...rest}
+  aria-describedby={hasError ? `${name}-error` : undefined}
+  {...rest}
 ...
-  alt={showPassword ? '비밀번호 보기' : '비밀번호 숨기기'}
+  alt=""
+  aria-label={showPassword ? '비밀번호 보기' : '비밀번호 숨기기'}
src/app/dashboard/[id]/Column/Column.tsx (1)

1-1: 사용되지 않는 useQueryClient import

이 파일에서는 useQueryClient가 참조되지 않습니다. 불필요한 import는 제거하여 번들 크기와 린트 경고를 줄이는 것이 좋습니다.

src/app/shared/components/common/Dropdown/Dropdown.tsx (2)

30-40: getWidthValue가 두 가지만 지원해 확장성이 떨어집니다

지금은 w-5, w-6만 하드코딩되어 있어 새로운 폭이 필요할 때마다 코드를 수정해야 합니다.
Tailwind theme('spacing')을 활용하거나 전달된 클래스에서 숫자를 추출해 rem으로 변환하도록 일반화하면 유지보수가 쉬워집니다.


126-133: 접근성 속성 추가 제안

트리거 요소에 aria-haspopup="menu"aria-expanded={open}를 부여하면 스크린리더가 드롭다운 상태를 올바르게 알릴 수 있습니다.

- <div
+ <div
+   aria-haspopup="menu"
+   aria-expanded={open}
   ref={triggerRef}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 769c5b6 and d9cdcac.

⛔ Files ignored due to path filters (6)
  • public/favicon.ico is excluded by !**/*.ico
  • public/favicon.png is excluded by !**/*.png
  • public/images/logo-dark.svg is excluded by !**/*.svg
  • public/images/logo-light2.svg is excluded by !**/*.svg
  • public/images/visibility-off.svg is excluded by !**/*.svg
  • public/images/visibility-on.svg is excluded by !**/*.svg
📒 Files selected for processing (37)
  • .github/workflows/ci.yml (1 hunks)
  • src/app/(auth)/login/page.tsx (1 hunks)
  • src/app/(auth)/signin/page.tsx (1 hunks)
  • src/app/dashboard/[id]/Card/Card.tsx (1 hunks)
  • src/app/dashboard/[id]/Card/Tags.tsx (1 hunks)
  • src/app/dashboard/[id]/Column/Column.tsx (3 hunks)
  • src/app/dashboard/[id]/api/updateCardColumn.ts (1 hunks)
  • src/app/dashboard/[id]/api/useCardMutation.ts (1 hunks)
  • src/app/dashboard/[id]/edit/layout.tsx (1 hunks)
  • src/app/dashboard/[id]/page.tsx (1 hunks)
  • src/app/dashboard/[id]/store/useDragStore.ts (1 hunks)
  • src/app/dashboard/[id]/type/Card.ts (1 hunks)
  • src/app/features/auth/components/AuthLogo.tsx (1 hunks)
  • src/app/features/auth/components/LoginForm.tsx (1 hunks)
  • src/app/features/auth/hooks/useAuth.ts (2 hunks)
  • src/app/features/auth/hooks/useLoginSubmit.ts (1 hunks)
  • src/app/features/auth/schemas/loginValidation.ts (1 hunks)
  • src/app/globals.css (3 hunks)
  • src/app/layout.tsx (1 hunks)
  • src/app/shared/components/Input.tsx (1 hunks)
  • src/app/shared/components/common/Avatar.tsx (1 hunks)
  • src/app/shared/components/common/CollaboratorItem.tsx (1 hunks)
  • src/app/shared/components/common/Dropdown/Dropdown.tsx (1 hunks)
  • src/app/shared/components/common/UserInfo.tsx (1 hunks)
  • src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx (1 hunks)
  • src/app/shared/components/common/header/Collaborator/Tooltip.tsx (1 hunks)
  • src/app/shared/components/common/header/Header.tsx (2 hunks)
  • src/app/shared/components/common/header/UserDropdown.tsx (1 hunks)
  • src/app/shared/components/common/sidebar/CreateDashboardButton.tsx (1 hunks)
  • src/app/shared/components/common/sidebar/DashboardItem.tsx (1 hunks)
  • src/app/shared/components/common/sidebar/Sidebar.tsx (1 hunks)
  • src/app/shared/lib/cn.ts (1 hunks)
  • src/app/shared/lib/getColor.ts (1 hunks)
  • src/app/shared/types/dashboard.ts (1 hunks)
  • src/app/tester/page.tsx (2 hunks)
  • tailwind.config.ts (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (18)
src/app/dashboard/[id]/edit/layout.tsx (1)
src/app/shared/components/common/sidebar/Sidebar.tsx (1)
  • Sidebar (10-110)
src/app/(auth)/login/page.tsx (1)
src/app/features/auth/components/LoginForm.tsx (1)
  • LoginForm (11-60)
src/app/features/auth/hooks/useAuth.ts (1)
src/app/features/auth/store/useAuthStore.ts (1)
  • useAuthStore (5-20)
src/app/dashboard/[id]/Card/Tags.tsx (1)
src/app/shared/lib/getColor.ts (1)
  • getColor (1-5)
src/app/shared/components/common/UserInfo.tsx (1)
src/app/shared/components/common/Avatar.tsx (1)
  • Avatar (32-61)
src/app/shared/components/common/CollaboratorItem.tsx (2)
src/app/shared/lib/cn.ts (1)
  • cn (4-6)
src/app/shared/components/common/Avatar.tsx (1)
  • Avatar (32-61)
src/app/features/auth/components/LoginForm.tsx (4)
src/app/features/auth/types/auth.type.ts (1)
  • LoginRequest (3-6)
src/app/features/auth/hooks/useLoginSubmit.ts (1)
  • useLoginSubmit (8-28)
src/app/features/auth/schemas/loginValidation.ts (1)
  • loginValidation (1-16)
src/app/shared/lib/cn.ts (1)
  • cn (4-6)
src/app/shared/components/common/sidebar/CreateDashboardButton.tsx (1)
src/app/shared/types/dashboard.ts (1)
  • CreateDashboardButtonProps (26-28)
src/app/shared/components/common/sidebar/Sidebar.tsx (2)
src/app/shared/components/common/sidebar/CreateDashboardButton.tsx (1)
  • CreateDashboardButton (7-27)
src/app/shared/components/common/sidebar/DashboardItem.tsx (1)
  • DashboardItem (7-47)
src/app/dashboard/[id]/store/useDragStore.ts (2)
src/app/dashboard/[id]/Card/Card.tsx (1)
  • Card (9-64)
src/app/dashboard/[id]/type/Card.ts (1)
  • Card (6-19)
src/app/shared/components/common/sidebar/DashboardItem.tsx (1)
src/app/shared/types/dashboard.ts (1)
  • DashboardItemProps (20-24)
src/app/dashboard/[id]/page.tsx (5)
src/app/api/useColumns.ts (1)
  • useColumns (27-32)
src/app/dashboard/[id]/store/useDragStore.ts (1)
  • useDragStore (13-17)
src/app/dashboard/[id]/api/useCardMutation.ts (1)
  • useCardMutation (8-102)
src/app/dashboard/[id]/Card/Card.tsx (1)
  • Card (9-64)
src/app/api/useCards.ts (1)
  • Card (11-24)
src/app/features/auth/hooks/useLoginSubmit.ts (2)
src/app/features/auth/hooks/useAuth.ts (1)
  • useAuth (5-34)
src/app/features/auth/types/auth.type.ts (1)
  • LoginRequest (3-6)
src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx (2)
src/app/shared/components/common/header/Collaborator/Tooltip.tsx (1)
  • Tooltip (12-70)
src/app/shared/components/common/CollaboratorItem.tsx (1)
  • CollaboratorItem (15-27)
src/app/dashboard/[id]/Card/Card.tsx (4)
src/app/api/useCards.ts (1)
  • Card (11-24)
src/app/dashboard/[id]/store/useDragStore.ts (1)
  • useDragStore (13-17)
src/app/dashboard/[id]/Card/Tags.tsx (1)
  • Tags (3-29)
src/app/shared/components/common/Avatar.tsx (1)
  • Avatar (32-61)
src/app/shared/components/Input.tsx (1)
src/app/shared/lib/cn.ts (1)
  • cn (4-6)
src/app/shared/components/common/Avatar.tsx (1)
src/app/shared/lib/getColor.ts (1)
  • getColor (1-5)
src/app/dashboard/[id]/api/useCardMutation.ts (4)
src/app/dashboard/[id]/store/useDragStore.ts (1)
  • useDragStore (13-17)
src/app/dashboard/[id]/type/Card.ts (1)
  • Card (6-19)
src/app/dashboard/[id]/api/updateCardColumn.ts (1)
  • updateCardColumn (4-12)
src/app/api/useCards.ts (1)
  • CardResponse (25-29)
🪛 actionlint (1.7.7)
.github/workflows/ci.yml

17-17: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🔇 Additional comments (14)
src/app/layout.tsx (1)

11-13: 파비콘 경로 변경 후 실제 파일 존재 여부 확인 필요
.ico 확장자로 변경된 것은 좋습니다만, /public/favicon.ico(또는 Next.js static 경로)에 실제 파일이 배치-되어 있지 않으면 404가 발생합니다. 배포 파이프라인에 해당 파일이 포함됐는지 한 번 더 점검해 주세요.

tsconfig.json (1)

28-30: Path alias 추가는 👍 하지만 정렬·중복 여부를 체크하세요
"@hooks/*""@lib/*" 가 새로 들어왔습니다.

  1. 기존 코드에서 상대경로 import 를 모두 alias 로 바꿨는지 점검해주세요.
  2. "@components/*""@hooks/*""@lib/*" 처럼 알파벳 순으로 정렬하면 diff 충돌을 줄일 수 있습니다.
    [ suggest_nitpick ]
src/app/globals.css (1)

53-55: Border-bottom 클래스 네이밍 충돌 가능성 확인 요청

Tailwind 기본 border-b 유틸리티와 의미가 겹쳐 팀원 혼동 여지가 큽니다. Border-section-bottom 등 프로젝트 컨벤션에 맞춘 보다 구체적인 접두사를 고려해 주세요.

src/app/dashboard/[id]/type/Card.ts (1)

14-15: teamId 타입 불일치 주의

다른 ID 필드가 모두 number인데 teamIdstring입니다. 백엔드 스키마와 의도적으로 맞춘 것인지 다시 한 번 확인 바랍니다.

src/app/dashboard/[id]/Card/Tags.tsx (1)

12-21: textColors[colorIndex] 계산 안전성 확인 필요
getColor의 두 번째 인자로 bgColors만 전달하고 있습니다. 만약 textColors 길이가 bgColors와 달라질 경우 범위를 벗어날 수 있습니다. 두 배열 길이를 항상 동일하게 관리하거나 getColor(tag, textColors)를 한 번 더 호출해 안전성을 확보하세요.

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

11-25: 구현 깔끔합니다!
접근성 레이블, 반응형 스타일 모두 적절합니다. 별다른 문제점이 보이지 않습니다.

src/app/(auth)/signin/page.tsx (1)

11-23: 불필요 중복 폼

LoginForm 컴포넌트가 이미 존재하는 상황에서 MyForm 이 동일 기능을 일부 중복 구현하고 있습니다. 유지보수를 위해 하나의 폼 구현으로 통합하거나 역할을 명확히 분리해 주세요.

src/app/tester/page.tsx (1)

23-77: 잘 구조화된 리팩토링입니다!

테스트 페이지가 애플리케이션의 일관된 레이아웃 패턴을 따르도록 Header와 Sidebar 컴포넌트를 적절히 통합했습니다.

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

1-47: 잘 구현된 컴포넌트입니다!

TypeScript 타입과 접근성을 적절히 고려하여 구현되었습니다.

src/app/dashboard/[id]/api/useCardMutation.ts (1)

8-102: 낙관적 업데이트 패턴이 잘 구현되었습니다

쿼리 취소, 캐시 업데이트, 에러 시 롤백 처리가 적절히 구현되었습니다.

src/app/dashboard/[id]/page.tsx (2)

66-66: 스크롤 방지 구현 계획 확인

드래그 중 스크롤 방지를 적용할 계획이신가요? 적용 시 사용자가 긴 목록을 스크롤할 수 없게 되므로 신중한 고려가 필요합니다.


23-121: 터치 기반 드래그 앤 드롭이 잘 구현되었습니다

롱 프레스 감지와 시각적 피드백이 적절히 구현되었습니다. 성능 최적화를 위해 requestAnimationFrame 적용을 고려해보세요.

src/app/shared/components/common/header/Header.tsx (1)

3-66: 깔끔한 모듈화 리팩토링입니다!

헤더 컴포넌트가 더 작은 컴포넌트들로 잘 분리되어 유지보수성이 향상되었습니다.

src/app/shared/components/common/Avatar.tsx (1)

36-48: Image 컴포넌트의 fill 사용 시크기 명시 필요 검토
fill 속성을 사용할 때는 부모 컨테이너의 position: relative & 고정 크기가 필수입니다. 현재 스타일로는 의도한 대로 동작하겠지만, Tailwind 클래스나 inline style 변경 시 레이아웃 붕괴 위험이 있으니 주석이나 테스트 추가를 권장합니다.

Comment on lines +19 to +23
screens: {
mobile: { max: '375px' },
tablet: { max: '744px' },
desktop: { max: '1920px' },
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

max breakpoint만 사용 시 의도치 않은 우선순위 충돌 가능
Tailwind 기본 sm(min 640px) 등과 조합될 때 모바일-우선이 깨질 수 있습니다.

screens: {
  mobile: '375px',      // min-width 기준
  tablet: { max: '744px' },
}

처럼 min/​max 개념을 명확히 분리하거나, 모든 커스텀 스크린을 min 으로 통일하는 방안을 검토해 주세요.

🤖 Prompt for AI Agents
In tailwind.config.ts around lines 19 to 23, the current use of only max-width
breakpoints can cause unintended priority conflicts with Tailwind's default
min-width breakpoints like 'sm'. To fix this, either convert all custom screen
definitions to use min-width values consistently or clearly separate min and max
breakpoints by defining mobile as a min-width breakpoint (e.g., mobile: '375px')
while keeping others as max-width if needed. This ensures predictable and
consistent responsive behavior without priority issues.

Comment on lines +11 to +18
dueDate: string
assignee: Assignee
imageUrl: string
teamId: string
dashboardId: number
columnId: number
createdAt: string
updatedAt: string
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

null 허용 여부 재검토

imageUrl, dueDate 필드는 API 응답 상 null일 가능성이 높습니다. 현재 string으로만 선언돼 있어 런타임에서 null 이 들어오면 타입 불일치 에러가 발생할 수 있습니다. 필요 시 string | null 또는 옵션(?)으로 수정해 주세요.

🤖 Prompt for AI Agents
In src/app/dashboard/[id]/type/Card.ts between lines 11 and 18, the fields
imageUrl and dueDate are currently typed as string but can be null based on API
responses. To fix this, update their types to string | null or make them
optional by adding a question mark, ensuring the type matches possible null
values and prevents runtime type errors.

Comment on lines 4 to 11
export async function updateCardColumn(
cardId: number,
columnId: number,
): Promise<{ success: boolean }> {
const res = await axiosClient.put<{ success: boolean }>(`/cards/${cardId}`, {
columnId: columnId,
})
return res.data
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

API 호출 실패 시 예외 처리가 누락되었습니다
네트워크 오류나 4xx/5xx 응답 시 예외가 상위로 전파되어 앱이 크래시할 수 있습니다. try-catch로 감싸고, 실패 시 적절한 에러 객체를 반환하거나 재-throw 하도록 개선해 주세요.

 export async function updateCardColumn(
   cardId: number,
   columnId: number,
 ): Promise<{ success: boolean }> {
-  const res = await axiosClient.put<{ success: boolean }>(`/cards/${cardId}`, {
-    columnId: columnId,
-  })
-  return res.data
+  try {
+    const res = await axiosClient.put<{ success: boolean }>(
+      `/cards/${cardId}`,
+      { columnId },
+    )
+    return res.data
+  } catch (error) {
+    // 필요하다면 Sentry 등으로 로깅
+    throw error
+  }
 }
📝 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 async function updateCardColumn(
cardId: number,
columnId: number,
): Promise<{ success: boolean }> {
const res = await axiosClient.put<{ success: boolean }>(`/cards/${cardId}`, {
columnId: columnId,
})
return res.data
export async function updateCardColumn(
cardId: number,
columnId: number,
): Promise<{ success: boolean }> {
try {
const res = await axiosClient.put<{ success: boolean }>(
`/cards/${cardId}`,
{ columnId },
)
return res.data
} catch (error) {
// 필요하다면 Sentry 등으로 로깅
throw error
}
}
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/api/updateCardColumn.ts around lines 4 to 11, the API
call using axiosClient.put lacks error handling, which can cause the app to
crash on network errors or 4xx/5xx responses. Wrap the axios call in a try-catch
block, and in the catch block either return a meaningful error object or
re-throw the error to ensure proper exception handling and prevent unhandled
promise rejections.

if (!oldData) return

const movedCard = { ...cardData, columnId: columnId }
console.log('Cardcolumn changed', { movedCard })
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

프로덕션 코드에서 console.log 제거 필요

-          console.log('Cardcolumn changed', { movedCard })
📝 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
console.log('Cardcolumn changed', { movedCard })
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/api/useCardMutation.ts at line 72, remove the
console.log statement used for debugging to ensure no debug logs remain in the
production code.

Comment on lines 66 to 78
queryClient.setQueryData<CardResponse>(
['columnId', columnId],
(oldData) => {
if (!oldData) return

const movedCard = { ...cardData, columnId: columnId }
console.log('Cardcolumn changed', { movedCard })
return {
...oldData,
cards: [...oldData.cards, movedCard],
}
},
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

setQueryData 콜백에서 올바른 반환값 필요

-          if (!oldData) return
+          if (!oldData) return oldData
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/api/useCardMutation.ts between lines 66 and 78, the
setQueryData callback does not always return a value, which is required. Modify
the callback to return the existing oldData when it is falsy instead of
returning undefined. This ensures the function consistently returns the expected
data structure.

Comment on lines 53 to 64
queryClient.setQueryData<CardResponse>(
['columnId', currentCard.cardData.columnId],
(oldData) => {
if (!oldData) return

const filtered = oldData.cards.filter((card) => {
return card.id !== cardData.id
})

return { ...oldData, cards: filtered }
},
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

setQueryData 콜백에서 올바른 반환값 필요

oldData가 없을 때도 기존 데이터를 반환해야 캐시 일관성이 유지됩니다.

-          if (!oldData) return
+          if (!oldData) return oldData
📝 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
queryClient.setQueryData<CardResponse>(
['columnId', currentCard.cardData.columnId],
(oldData) => {
if (!oldData) return
const filtered = oldData.cards.filter((card) => {
return card.id !== cardData.id
})
return { ...oldData, cards: filtered }
},
)
queryClient.setQueryData<CardResponse>(
['columnId', currentCard.cardData.columnId],
(oldData) => {
if (!oldData) return oldData
const filtered = oldData.cards.filter((card) => {
return card.id !== cardData.id
})
return { ...oldData, cards: filtered }
},
)
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/api/useCardMutation.ts around lines 53 to 64, the
setQueryData callback currently returns undefined when oldData is falsy, which
breaks cache consistency. Modify the callback to return the existing oldData
unchanged when it is falsy, ensuring the cache remains consistent by always
returning a valid data object.

Comment on lines 14 to +22
const dashboard = 15120
const { data: columns, isLoading, error } = useColumns(dashboard)
const { draggingCard, setDraggingCard } = useDragStore()
const cardMutation = useCardMutation()
const touchPos = useRef({ x: 0, y: 0 })
const prevColumn = useRef<HTMLElement | null>(null)
const longPressTimer = useRef<number | null>(null)
const isLongPressActive = useRef(false)

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

컴포넌트 언마운트 시 타이머 정리 필요

컴포넌트가 언마운트될 때 활성 타이머를 정리하지 않으면 메모리 누수가 발생할 수 있습니다.

import { useEffect } from 'react'

// 컴포넌트 내부에 추가
useEffect(() => {
  return () => {
    if (longPressTimer.current) {
      clearTimeout(longPressTimer.current)
    }
    const clone = document.getElementById('dragged-clone')
    if (clone) {
      clone.remove()
    }
  }
}, [])
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/page.tsx around lines 14 to 22, the longPressTimer set
with useRef is not cleared on component unmount, which can cause memory leaks.
Add a useEffect hook that returns a cleanup function to clear the longPressTimer
if it exists and remove the element with id 'dragged-clone' from the DOM when
the component unmounts.


// 1. 🧱 클론 카드 제거
const clone = document.getElementById('dragged-clone')
if (clone && isLongPressActive) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

ref 값 접근 오류 수정 필요

isLongPressActive는 ref이므로 .current를 사용해야 합니다.

-    if (clone && isLongPressActive) {
+    if (clone && isLongPressActive.current) {
📝 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 (clone && isLongPressActive) {
if (clone && isLongPressActive.current) {
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/page.tsx at line 97, the condition incorrectly
accesses the ref variable isLongPressActive directly. Since isLongPressActive is
a ref, update the condition to use isLongPressActive.current to properly access
its value.

Comment on lines 36 to 53
onDrop={(e) => {
e.preventDefault()
if (isDraggingover) setDraggingover(false)
const draggingCard = useDragStore.getState().draggingCard
if (!draggingCard) {
console.log('no dragging card') //TODO - toast 처리 🍞
return
}

if (draggingCard.cardData.columnId === id) {
clearDraggingCard()
return
}
cardMutation.mutate({
columnId: id,
cardData: draggingCard.cardData,
})
}}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

드래그 종료 후 전역 dragging 상태가 정리되지 않습니다

mutate 호출이 완료되어도 draggingCard가 그대로 남아 있어 다음 드래그에 영향을 줄 수 있습니다.
onSettled 혹은 finally 콜백에서 clearDraggingCard()를 호출해 상태를 항상 초기화해 주세요.

 cardMutation.mutate(
   {
     columnId: id,
     cardData: draggingCard.cardData,
   },
-)
+{
+  onSettled: () => clearDraggingCard(),
+})
🤖 Prompt for AI Agents
In src/app/dashboard/[id]/Column/Column.tsx between lines 36 and 53, the global
dragging state is not cleared after the mutate call completes, which can affect
subsequent drag operations. To fix this, add a callback such as onSettled or
finally to the cardMutation.mutate call and invoke clearDraggingCard() there to
ensure the dragging state is always reset regardless of mutation success or
failure.

@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
coderabbitai bot added a commit that referenced this pull request Jun 16, 2025
Docstrings generation was requested by @dkslel1225.

* #55 (comment)

The following files were modified:

* `src/app/dashboard/[id]/Card/Card.tsx`
* `src/app/dashboard/[id]/Card/Tags.tsx`
* `src/app/dashboard/[id]/Column/Column.tsx`
* `src/app/dashboard/[id]/page.tsx`
* `src/app/shared/components/common/Avatar.tsx`
* `src/app/shared/lib/getColor.ts`
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
@CoPlay-FE CoPlay-FE deleted a comment from coderabbitai bot Jun 16, 2025
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.

터치 이벤트 수고 하셨습니다! 터치 이벤트에 대해서도 간략하게 설명해주셔서 흐름을 이해할 수 있었습니다 👍 👍

Copy link

@LeeCh0129 LeeCh0129 left a comment

Choose a reason for hiding this comment

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

드래그 앤 드롭 고생하셨습니다~
상세 설명과 동영상까지 올려주셔서 어떤 플로우로 동작하는지 이해가 잘되네요 👍👍

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 +5
export function getColor(text: string, customColors: string[]): number {
const hash = text.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
const index = hash % customColors.length
return index
}
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분은 공용 유틸 함수로 아래처럼 뺄 수 있을 것 같네용

export function getHashedColorIndex(text: string, colorArrayLength: number): number {
  const hash = text.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
  return hash % colorArrayLength
}

Copy link
Contributor Author

@dkslel1225 dkslel1225 Jun 17, 2025

Choose a reason for hiding this comment

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

앗 그러네요, 다음번 PR에서 수정하겠습니당

@dkslel1225 dkslel1225 merged commit 09d3ec7 into feature/dashboard_id Jun 17, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔧Chore 설정, 빌드 변경 ✨Feat 기능 개발 🎨Style UI, 스타일 관련 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Feat: 대시보드 상세 페이지 - 드래그 앤 드롭

5 participants