Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 결과 수정 페이지 퍼블리싱 및 DND 모듈 구현 #108

Merged
merged 11 commits into from
Feb 6, 2025

Conversation

minseong0324
Copy link
Contributor

@minseong0324 minseong0324 commented Feb 6, 2025

관련 이슈

close: #107

변경 사항

결과 수정 - 상세 페이지에서도 사용할 수 있도록 DND 모듈을 구현했어요.

그리고, 업로드 예약 페이지에서도 어느정도 재사용이 가능할 것 같아 일부 컴포넌트 및 유틸을 components/common, utils 하위로 옮겼어요.

2025-02-06.11.06.59.mov

레퍼런스

Summary by CodeRabbit

  • 새로운 기능
    • 드래그 앤 드롭 인터페이스가 대폭 강화되어 콘텐츠 항목을 직관적으로 정렬 및 관리할 수 있습니다.
    • 콘텐츠 편집 화면과 관련 UI 요소가 추가되어 섹션별 항목 관리가 용이해졌습니다.
    • 실시간 업데이트 시간 정보가 표시되어 최신 상태를 한눈에 확인할 수 있습니다.
    • 드래그 앤 드롭 가이드를 제공하는 새로운 컴포넌트가 추가되었습니다.
  • 유지보수
    • 드래그 앤 드롭 관련 신규 라이브러리 의존성이 추가되고, 기존 의존성 순서가 개선되었습니다.
    • 임포트 경로 및 스타일 구성이 정리되어 코드 구조가 향상되었습니다.

Copy link

coderabbitai bot commented Feb 6, 2025

Warning

Rate limit exceeded

@minseong0324 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 4 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 762e230 and 73afc04.

📒 Files selected for processing (11)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/Edit.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/detail/_components/PostEditor/PostEditor.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/DndController.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/compounds/ContentItem/ContentItem.css.ts (1 hunks)
  • apps/web/src/components/common/DNDController/compounds/ContentItem/ContentItem.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/compounds/DraggableContentItem/DraggableContentItem.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/compounds/DroppableContent/DroppableContent.css.ts (1 hunks)
  • apps/web/src/components/common/DNDController/compounds/DroppableContent/DroppableContent.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/context/DndContext.tsx (1 hunks)
  • apps/web/src/components/common/DNDController/hooks/useDragAndDrop.ts (1 hunks)
  • apps/web/src/components/common/index.ts (1 hunks)

Walkthrough

이번 PR은 결과 수정 페이지와 드래그 앤 드롭(DND) 모듈을 구현하기 위해 다양한 컴포넌트, 훅, 컨텍스트, 스타일 파일 및 유틸리티 함수들을 추가 및 수정하였습니다. 새로운 의존성 추가와 함께 DND 관련 컴포넌트(예: DndControler, ContentItem, DraggableContentItem, DroppableContent) 및 관련 후크와 컨텍스트, DragGuide 컴포넌트가 도입되었으며, 편집 페이지와 관련된 상수, 타입, 스타일 및 경로 수정도 포함되어 있습니다.

Changes

파일(경로) 변경 내용
apps/web/package.json DND 관련 의존성(@dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities) 추가 및 기존 ky 의존성 순서 변경
apps/web/src/components/common/DND/... DND 모듈 구현: DndControler, ContentItem, DraggableContentItem, DroppableContent, 관련 CSS/스타일 파일, 컨텍스트(DndContext), 후크(useDragAndDrop) 추가
apps/web/src/utils/{getTimeAgo,index}.ts, MainBreadcrumbItem.tsx 시간 차이 계산 유틸리티 함수 추가 및 내보내기, Breadcrumb 컴포넌트로 구조 변경 및 이미지 크기 업데이트
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/... 결과 수정 페이지 구현: Edit 페이지, DragGuide 컴포넌트, 상수(INITIAL_CONTENT_ITEMS), 타입, 스타일 파일 추가 및 기존 페이지 경로 수정/제거

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant Edit as EditPage
    participant Dnd as DndContext
    participant Item as DraggableContentItem
    User->>Edit: 페이지 로드 및 드래그 시작
    Edit->>Dnd: DND 초기화 및 이벤트 전달
    Dnd->>Item: 드래그/드랍 이벤트 전달
    User->>Item: 항목 이동 및 드랍
    Dnd->>Edit: 드래그 종료 후 상태 업데이트
Loading

Assessment against linked issues

Objective Addressed Explanation
결과 수정 페이지 퍼블리싱 [#107]
DND 모듈 구현 [#107]

Suggested reviewers

  • kongnayeon

Poem

작은 토끼의 변화 송가,
코드 숲 사이를 가볍게 뛰노네,
새 의존성은 푸른 꿈을 싣고,
드래그 앤 드롭 춤을 추며,
UI에 봄바람 불어오길,
🐰💻 변화에 기쁨이 깃들길!
Hop, hop, 행복한 코드의 날!


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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: 4

🧹 Nitpick comments (16)
apps/web/src/components/common/DND/compounds/DraggableContentItem/DraggableContentItem.tsx (2)

13-26: data 객체의 중복된 id 속성을 개선할 수 있습니다.

useSortable 설정에서 data 객체의 id 속성이 상위 id 속성과 중복됩니다. 또한 type 속성의 값이 문자열 리터럴로 하드코딩되어 있습니다.

다음과 같이 개선해보세요:

  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({
    id: id,
    data: {
-     type: 'item',
-     id: id,
+     type: 'item' as const,
    },
  });

9-44: 성능 최적화를 위한 메모이제이션 검토가 필요합니다.

드래그 앤 드롭 작업은 빈번한 리렌더링을 유발할 수 있습니다. 컴포넌트를 React.memo로 감싸서 불필요한 리렌더링을 방지하는 것을 고려해보세요.

- export function DraggableContentItem({
+ export const DraggableContentItem = React.memo(function DraggableContentItem({
  id,
  ...contentItemProps
}: DraggableContentItemProps) {
  // ... existing implementation
- }
+ });
apps/web/src/components/common/DND/compounds/DroppableContent/DroppableContent.css.ts (1)

3-9: 컨테이너 높이 설정을 더 유연하게 개선하면 좋을 것 같습니다.

현재 고정된 최소 높이(minHeight: '20rem')는 다양한 화면 크기나 컨텐츠 양에 따라 제한적일 수 있습니다. 반응형 디자인을 위해 다음과 같은 개선을 고려해보세요:

 export const droppableContainer = style({
-  minHeight: '20rem',
+  minHeight: 'min(20rem, 50vh)',
   height: '100%',
   display: 'flex',
   flexDirection: 'column',
   position: 'relative',
 });
apps/web/src/components/common/DND/compounds/DroppableContent/DroppableContent.tsx (1)

10-24: 드롭 영역 구현이 잘 되어있습니다.

다만, 타입 안전성을 더욱 강화하기 위해 accepts 배열의 타입을 상수로 정의하는 것을 고려해보세요.

+const ACCEPTED_TYPES = ['item'] as const;
+type AcceptedType = typeof ACCEPTED_TYPES[number];

 export function DroppableContent({ id, children }: DroppableContentProps) {
   const { setNodeRef } = useDroppable({
     id,
     data: {
       type: 'container',
-      accepts: ['item'],
+      accepts: ACCEPTED_TYPES,
     },
   });
apps/web/src/app/edits/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.tsx (1)

21-25: 이미지 접근성을 개선해주세요.

alt 텍스트가 한국어로만 제공되어 있습니다. 국제화를 고려하여 alt 텍스트를 다국어로 제공하는 것이 좋습니다.

 <Image
   src={DNDImage}
-  alt="드래그 앤 드롭 이미지"
+  alt={t('common.dnd.guide.image.alt', '드래그 앤 드롭 이미지')}
   className={styles.image}
 />
apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.tsx (1)

8-11: Props 타입 정의를 개선할 수 있습니다.

onClick이 제공되지 않은 경우의 처리를 타입 시스템에서 명확히 할 수 있습니다.

-type MainBreadcrumbItemProps = {
-  href?: string;
-  onClick?: () => void;
-};
+type MainBreadcrumbItemProps =
+  | { href: string; onClick?: never }
+  | { href?: string; onClick: () => void };
apps/web/src/components/common/DND/DndControler.tsx (2)

10-13: 타입 안전성 개선이 필요합니다.

items 타입을 (number | string)[]로 제한하는 것은 너무 제한적일 수 있습니다. 제네릭을 사용하여 더 유연한 타입 지원을 고려해보세요.

-type SortableListProps = {
-  items: (number | string)[];
-  children: ReactNode;
-};
+type SortableListProps<T extends number | string> = {
+  items: T[];
+  children: ReactNode;
+};

23-27: 컴파운드 컴포넌트에 대한 문서화가 필요합니다.

각 서브 컴포넌트의 용도와 사용법에 대한 JSDoc 문서를 추가하면 좋을 것 같습니다.

apps/web/src/components/common/DND/compounds/ContentItem/ContentItem.css.ts (2)

25-33: 접근성 개선이 필요합니다.

hover 상태에 의존하는 UI는 터치 디바이스나 키보드 사용자에게 접근이 어려울 수 있습니다. focus-visible과 같은 추가적인 상태를 고려해보세요.

export const timeStyle = style({
  display: 'block',

  selectors: {
    [`${contentItemStyle}:hover &`]: {
      display: 'none',
    },
+   [`${contentItemStyle}:focus-visible &`]: {
+     display: 'none',
+   },
  },
});

3-11: 반응형 디자인 고려가 필요합니다.

고정된 크기 값들을 사용하고 있습니다. 다양한 화면 크기에 대응할 수 있도록 미디어 쿼리 추가를 고려해보세요.

apps/web/src/app/edits/[agentId]/[postGroupId]/pageStyle.css.ts (1)

39-42: 유연한 레이아웃 구현이 필요합니다.

고정된 width 값을 사용하면 작은 화면에서 문제가 될 수 있습니다. 반응형 디자인을 위해 상대적인 단위 사용을 고려해보세요.

export const accordionItemStyle = style({
-  width: '51.2rem',
+  width: 'min(51.2rem, 100%)',
  flex: '0 0 auto',
});
apps/web/src/utils/getTimeAgo.ts (1)

7-48: 국제화(i18n) 지원 추가를 고려해보세요.

현재 한국어로 하드코딩된 문자열들이 있습니다. 다국어 지원을 위해 메시지를 분리하는 것이 좋을 것 같습니다.

또한, 월과 년 계산에서 고정된 일수를 사용하고 있습니다. 더 정확한 계산을 위해 실제 달력 기반의 계산을 고려해보세요.

- const months = Math.floor(diffInSeconds / (86400 * 30));
+ const months = now.getMonth() - inputDate.getMonth() + 
+   (now.getFullYear() - inputDate.getFullYear()) * 12;
apps/web/src/app/edits/[agentId]/[postGroupId]/constants.ts (2)

4-5: 더미 데이터 주석 개선이 필요합니다.

//MEMO: 임시 더미 주석은 임시 데이터임을 나타내지만, 실제 데이터로 교체해야 하는 시점이나 조건을 명시하지 않고 있습니다.

다음과 같이 TODO 주석으로 변경하는 것을 제안합니다:

-//MEMO: 임시 더미
+// TODO: 실제 API 연동 시 제거 필요

8-20: 날짜 생성 방식 개선이 필요합니다.

각 포스트마다 new Date().toISOString()를 사용하면 테스트 시 일관성 없는 타임스탬프가 생성될 수 있습니다.

고정된 날짜를 사용하거나 상대적인 날짜를 사용하는 것을 추천드립니다:

-    createdAt: new Date().toISOString(),
-    updatedAt: new Date().toISOString(),
-    uploadTime: new Date().toISOString(),
+    createdAt: '2025-02-01T00:00:00.000Z',
+    updatedAt: '2025-02-01T00:00:00.000Z',
+    uploadTime: '2025-02-01T00:00:00.000Z',

Also applies to: 24-30, 34-40, 44-50, 54-60

apps/web/src/components/common/DND/hooks/useDragAndDrop.ts (2)

44-53: 드래그 방향 로직이 복잡합니다.

최종 삽입 위치를 계산하는 로직이 다소 복잡하게 구현되어 있습니다. 이는 유지보수를 어렵게 만들 수 있습니다.

다음과 같이 로직을 단순화하는 것을 제안합니다:

-        // 드래그 방향이 아래쪽인지 확인
-        const isBelow = event.delta.y > 0;
-
-        // 최종 삽입 위치 계산
-        let finalIndex = newIndex;
-        if (oldIndex < newIndex && !isBelow) {
-          finalIndex--;
-        } else if (oldIndex > newIndex && isBelow) {
-          finalIndex++;
-        }
+        const finalIndex = event.delta.y > 0 ? newIndex + 1 : newIndex;

129-131: 아이템 제거 로직이 단순 필터링만 수행합니다.

handleRemove 함수가 아이템을 제거할 때 사용자 확인이나 실행 취소 기능을 제공하지 않습니다.

삭제 전 확인 단계를 추가하고, 실행 취소 기능을 구현하는 것을 고려해보세요.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 692ee0a and 784033d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • apps/web/package.json (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/Edit.tsx (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.css.ts (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.tsx (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/constants.ts (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/page.tsx (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/pageStyle.css.ts (1 hunks)
  • apps/web/src/app/edits/[agentId]/[postGroupId]/types.ts (1 hunks)
  • apps/web/src/components/common/DND/DndControler.tsx (1 hunks)
  • apps/web/src/components/common/DND/compounds/ContentItem/ContentItem.css.ts (1 hunks)
  • apps/web/src/components/common/DND/compounds/ContentItem/ContentItem.tsx (1 hunks)
  • apps/web/src/components/common/DND/compounds/DraggableContentItem/DraggableContentItem.tsx (1 hunks)
  • apps/web/src/components/common/DND/compounds/DroppableContent/DroppableContent.css.ts (1 hunks)
  • apps/web/src/components/common/DND/compounds/DroppableContent/DroppableContent.tsx (1 hunks)
  • apps/web/src/components/common/DND/context/DndContext.tsx (1 hunks)
  • apps/web/src/components/common/DND/hooks/useDragAndDrop.ts (1 hunks)
  • apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.tsx (2 hunks)
  • apps/web/src/utils/getTimeAgo.ts (1 hunks)
  • apps/web/src/utils/index.ts (1 hunks)
🔇 Additional comments (16)
apps/web/src/components/common/DND/compounds/DraggableContentItem/DraggableContentItem.tsx (3)

1-3: 필요한 모든 의존성이 올바르게 임포트되었습니다!

DND 기능 구현에 필요한 라이브러리들과 베이스 컴포넌트가 적절하게 임포트되었습니다.


5-7: 타입 정의가 명확하고 간결합니다!

Omit을 사용하여 기존 props에서 dragListeners를 제거하고 id를 추가한 것이 적절합니다.


28-43: 컴포넌트 구현이 깔끔하고 효율적입니다!

스타일 적용과 props 전달이 적절하게 구현되었습니다. 특히 드래그 중인 상태에 따른 투명도 처리가 UX 측면에서 좋습니다.

apps/web/src/utils/index.ts (1)

3-3: 코드가 깔끔하고 명확합니다!

유틸리티 함수의 내보내기가 잘 구성되어 있습니다.

apps/web/src/app/edits/[agentId]/[postGroupId]/types.ts (1)

1-8: 타입 정의가 명확하고 잘 구성되어 있습니다!

페이지 props와 params에 대한 타입이 명확하게 정의되어 있어 타입 안정성을 보장합니다.

apps/web/src/app/edits/[agentId]/[postGroupId]/page.tsx (1)

4-6: 페이지 컴포넌트가 깔끔하게 구현되어 있습니다!

Next.js의 페이지 구조를 잘 따르고 있으며, 타입 안정성이 보장된 props 전달이 잘 되어 있습니다.

apps/web/src/components/common/DND/compounds/DroppableContent/DroppableContent.tsx (1)

5-8: 타입 정의가 명확하고 간단합니다!

props 인터페이스가 잘 정의되어 있습니다.

apps/web/src/app/edits/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.css.ts (2)

4-17: 컨테이너 스타일링이 잘 구현되어 있습니다!

디자인 시스템의 변수들을 일관성 있게 잘 활용하고 있습니다.


24-29: 이미지 반응형 처리가 잘 되어 있습니다!

최대 너비와 높이를 지정하여 레이아웃 깨짐을 방지한 점이 좋습니다.

apps/web/src/components/common/MainBreadcrumbItem/MainBreadcrumbItem.tsx (1)

31-36: 이미지 최적화가 잘 되어 있습니다!

next/image를 사용하여 이미지 최적화를 구현한 점이 좋습니다.

apps/web/src/utils/getTimeAgo.ts (1)

16-19: TODO 해결이 필요합니다.

1분 미만의 시간 표시에 대한 논의가 필요하다는 TODO가 있습니다. 사용자 경험을 위해 이 부분을 명확히 결정하고 구현해야 합니다.

apps/web/src/components/common/DND/context/DndContext.tsx (2)

84-89: 빈 콜백 함수 개선이 필요합니다.

onModify 콜백이 빈 함수로 구현되어 있습니다. 이는 사용자가 수정 버튼을 클릭했을 때 아무런 반응이 없다는 것을 의미합니다.

수정 기능이 아직 구현되지 않은 것인지, 아니면 실수로 누락된 것인지 확인이 필요합니다.


44-47: 드래그 감지 설정이 적절합니다.

마우스와 터치 센서에 대해 5픽셀의 활성화 제약을 설정한 것은 우수한 구현입니다. 이는 실수로 인한 드래그를 방지하는데 도움이 됩니다.

apps/web/src/components/common/DND/compounds/ContentItem/ContentItem.tsx (1)

17-43: Props 타입 정의가 잘 되어있습니다.

각 prop에 대한 JSDoc 주석이 명확하게 작성되어 있어 컴포넌트 사용 시 이해하기 쉽습니다.

apps/web/src/app/edits/[agentId]/[postGroupId]/Edit.tsx (1)

1-23: 타입 정의와 임포트가 잘 구성되어 있습니다!

컴포넌트의 타입 정의와 필요한 모듈들이 잘 구성되어 있습니다.

apps/web/package.json (1)

14-16: @dnd-kit 패키지들의 버전 호환성 확인이 필요합니다.

새로 추가된 @dnd-kit 패키지들의 버전이 서로 호환되는지 확인이 필요합니다.

✅ Verification successful

🌐 Web query:

What are the latest compatible versions of @dnd-kit/core, @dnd-kit/sortable, and @dnd-kit/utilities packages?

💡 Result:

The latest compatible versions of `@dnd-kit` packages as of February 2025 are:

## Core Packages
| Package               | Latest Version | Compatibility Notes |
|-----------------------|----------------|---------------------|
| `@dnd-kit/core`       | **6.3.1**      | Peer dependency for other packages [1][8] |
| `@dnd-kit/sortable`   | **10.0.0**     | Requires `@dnd-kit/core@^6.x` [2][6] |
| `@dnd-kit/utilities` | **3.2.x**      | Compatible with all v6.x core packages [1][7] |

### Key Details:
- **Core Dependency Chain**:  
  - `@dnd-kit/[email protected]` lists `@dnd-kit/core@^6.x` as a peer dependency [2][6]
  - Recent modifier package updates (e.g., `@dnd-kit/[email protected]`) require `[email protected]` [1]
  
- **Version Alignment**:
  ```markdown
  - Core:      6.x (breaking changes in major versions)
  - Sortable:  10.x (matches core major version +4)
  - Utilities: 3.x (aligned with core via semantic versioning)
  ```

### Installation Recommendation:
```bash
npm install @dnd-kit/[email protected] @dnd-kit/[email protected] @dnd-kit/[email protected]
```

Note: The packages follow React 18+ compatibility and modern browser targeting requirements established in v5+ releases[1][5]. Always verify peer dependency warnings during installation for exact version matching[1][2].

Citations:

- 1: https://github.com/clauderic/dnd-kit/blob/master/packages/modifiers/CHANGELOG.md
- 2: https://www.npmjs.com/package/@dnd-kit/sortable
- 3: https://github.com/clauderic/dnd-kit/
- 4: https://classic.yarnpkg.com/en/package/@dnd-kit/core
- 5: https://github.com/clauderic/dnd-kit/releases
- 6: https://classic.yarnpkg.com/en/package/@dnd-kit/sortable
- 7: https://www.npmjs.com/package/@dnd-kit/utilities
- 8: https://www.npmjs.com/package/@dnd-kit/core
- 9: https://docs.dndkit.com/presets/sortable
- 10: https://classic.yarnpkg.com/en/package/@dnd-kit/utilities

@dnd-kit 패키지 버전 호환성 확인 완료

  • 현재 package.json에 명시된 버전("@dnd-kit/core: ^6.3.1", "@dnd-kit/sortable: ^10.0.0", "@dnd-kit/utilities: ^3.2.2")은 최신 호환 버전과 일치합니다.
  • 웹 쿼리 결과에서도 해당 버전들이 서로 호환되며, 특히 @dnd-kit/sortable@dnd-kit/core@^6.x를 요구하는 점도 확인되었습니다.

Comment on lines 76 to 78
{image ? (
<div>x</div>
) : (
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

이미지 플레이스홀더 구현이 미흡합니다.

현재 이미지 플레이스홀더가 단순한 'x' 문자로 구현되어 있습니다. 이는 사용자 경험 측면에서 적절하지 않습니다.

다음과 같이 의미 있는 플레이스홀더 구현을 제안합니다:

-          <div>x</div>
+          <img
+            src={image}
+            alt="콘텐츠 이미지"
+            onError={(e) => {
+              e.currentTarget.src = '/placeholder-image.png';
+            }}
+          />
📝 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
{image ? (
<div>x</div>
) : (
{image ? (
<img
src={image}
alt="콘텐츠 이미지"
onError={(e) => {
e.currentTarget.src = '/placeholder-image.png';
}}
/>
) : (

apps/web/src/app/edits/[agentId]/[postGroupId]/Edit.tsx Outdated Show resolved Hide resolved
Comment on lines 178 to 191
onDragEnd={(items) => {
console.log('=== Current Items Status ===');
const itemsByStatus = {
GENERATED: items.filter((item) => item.status === 'GENERATED'),
EDITING: items.filter((item) => item.status === 'EDITING'),
READY_TO_UPLOAD: items.filter(
(item) => item.status === 'READY_TO_UPLOAD'
),
};
console.log('GENERATED:', itemsByStatus.GENERATED);
console.log('EDITING:', itemsByStatus.EDITING);
console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
console.log('========================');
}}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

프로덕션 코드에서 console.log 제거 및 에러 처리 추가가 필요합니다.

  1. 프로덕션 환경에서는 console.log를 제거하는 것이 좋습니다.
  2. DND 작업 중 발생할 수 있는 에러 처리가 필요합니다.
       onDragEnd={(items) => {
-        console.log('=== Current Items Status ===');
-        const itemsByStatus = {
-          GENERATED: items.filter((item) => item.status === 'GENERATED'),
-          EDITING: items.filter((item) => item.status === 'EDITING'),
-          READY_TO_UPLOAD: items.filter(
-            (item) => item.status === 'READY_TO_UPLOAD'
-          ),
-        };
-        console.log('GENERATED:', itemsByStatus.GENERATED);
-        console.log('EDITING:', itemsByStatus.EDITING);
-        console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
-        console.log('========================');
+        try {
+          const itemsByStatus = {
+            GENERATED: items.filter((item) => item.status === 'GENERATED'),
+            EDITING: items.filter((item) => item.status === 'EDITING'),
+            READY_TO_UPLOAD: items.filter(
+              (item) => item.status === 'READY_TO_UPLOAD'
+            ),
+          };
+          // TODO: 상태 업데이트 로직 구현
+        } catch (error) {
+          // TODO: 에러 처리 로직 구현
+        }
📝 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
onDragEnd={(items) => {
console.log('=== Current Items Status ===');
const itemsByStatus = {
GENERATED: items.filter((item) => item.status === 'GENERATED'),
EDITING: items.filter((item) => item.status === 'EDITING'),
READY_TO_UPLOAD: items.filter(
(item) => item.status === 'READY_TO_UPLOAD'
),
};
console.log('GENERATED:', itemsByStatus.GENERATED);
console.log('EDITING:', itemsByStatus.EDITING);
console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
console.log('========================');
}}
onDragEnd={(items) => {
try {
const itemsByStatus = {
GENERATED: items.filter((item) => item.status === 'GENERATED'),
EDITING: items.filter((item) => item.status === 'EDITING'),
READY_TO_UPLOAD: items.filter(
(item) => item.status === 'READY_TO_UPLOAD'
),
};
// TODO: 상태 업데이트 로직 구현
} catch (error) {
// TODO: 에러 처리 로직 구현
}
}}

Comment on lines 78 to 91
items={getItemsByStatus(POST_STATUS.GENERATED).map(
(item) => item.id
)}
>
{getItemsByStatus(POST_STATUS.GENERATED).map((item) => (
<DndControler.Item
key={item.id}
id={item.id}
summary={item.summary}
updatedAt={item.updatedAt}
onRemove={() => handleRemove(item.id)}
onModify={() => {}}
/>
))}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

getItemsByStatus 호출 최적화가 필요합니다.

현재 getItemsByStatus가 map 내부에서 반복적으로 호출되고 있습니다. 성능 최적화를 위해 다음과 같이 수정하는 것을 추천드립니다:

-                <DndControler.SortableList
-                  items={getItemsByStatus(POST_STATUS.GENERATED).map(
-                    (item) => item.id
-                  )}
-                >
-                  {getItemsByStatus(POST_STATUS.GENERATED).map((item) => (
+                {const generatedItems = getItemsByStatus(POST_STATUS.GENERATED);
+                <DndControler.SortableList
+                  items={generatedItems.map((item) => item.id)}
+                >
+                  {generatedItems.map((item) => (

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

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: 5

🧹 Nitpick comments (7)
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.tsx (2)

21-25: 이미지 접근성 개선이 필요합니다.

이미지의 alt 텍스트가 "드래그 앤 드롭 이미지"로 일반적입니다. 이미지가 전달하는 구체적인 안내 내용을 포함하면 좋겠습니다.

-        alt="드래그 앤 드롭 이미지"
+        alt="콘텐츠를 드래그하여 원하는 위치로 이동할 수 있습니다"

13-20: 텍스트 접근성 개선이 필요합니다.

Text.H2 컴포넌트에 aria-label을 추가하여 스크린 리더 사용자에게 더 명확한 컨텍스트를 제공하면 좋겠습니다.

       <Text.H2
         className={styles.description}
         fontSize={20}
         fontWeight="semibold"
         color="grey500"
+        aria-label="드래그 앤 드롭 가이드"
       >
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.css.ts (2)

24-29: 반응형 디자인 개선이 필요합니다.

이미지 크기가 고정된 rem 값을 사용하고 있어 작은 화면에서 문제가 될 수 있습니다. 뷰포트 기반의 상대적인 크기를 사용하는 것이 좋겠습니다.

 export const image = style({
   width: '100%',
   height: '100%',
-  maxWidth: '42rem',
-  maxHeight: '12.8rem',
+  maxWidth: 'min(42rem, 90vw)',
+  maxHeight: 'min(12.8rem, 30vh)',
 });

4-17: 모바일 환경을 고려한 패딩 조정이 필요합니다.

컨테이너의 패딩이 모든 화면 크기에서 동일하게 적용됩니다. 작은 화면에서는 패딩을 줄이는 것이 좋겠습니다.

 export const container = style({
   display: 'flex',
   alignItems: 'center',
   justifyContent: 'center',
   flexDirection: 'column',
   width: '100%',
   height: 'fit-content',
   borderRadius: vars.borderRadius[24],
   border: `1px solid ${vars.colors.grey50}`,
   background: vars.colors.grey,
-  padding: vars.space[40],
+  padding: `min(${vars.space[40]}, 5vw)`,
   gap: vars.space[32],
   alignSelf: 'stretch',
 });
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/pageStyle.css.ts (1)

34-37: 고정 높이 값에 대한 검토가 필요합니다.

height: '8rem'은 내용이 길어질 경우 텍스트 잘림 현상을 일으킬 수 있습니다.

다음과 같이 수정하는 것을 고려해보세요:

export const accordionTriggerStyle = style({
-  height: '8rem',
+  minHeight: '8rem',
  padding: `${vars.space[12]} ${vars.space[16]}`,
});
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/constants.ts (1)

4-62: 더미 데이터의 다양성 개선이 필요합니다.

모든 아이템이 동일한 상태(GENERATED)를 가지고 있어 다양한 상태에 대한 테스트가 어렵습니다.

일부 아이템의 상태를 EDITINGREADY_TO_UPLOAD로 변경하여 다양한 시나리오를 테스트할 수 있도록 하는 것을 추천합니다.

apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/Edit.tsx (1)

78-82: 성능 최적화가 필요합니다.

getItemsByStatus 함수가 렌더링마다 반복적으로 호출되고 있습니다.

useMemo를 사용하여 불필요한 계산을 방지하는 것을 권장합니다:

+ const generatedItems = useMemo(
+   () => getItemsByStatus(POST_STATUS.GENERATED),
+   [getItemsByStatus]
+ );

<DndControler.SortableList
-  items={getItemsByStatus(POST_STATUS.GENERATED).map(
+  items={generatedItems.map(
     (item) => item.id
   )}
>

Also applies to: 108-111, 142-145

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 784033d and f82061f.

📒 Files selected for processing (10)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/Edit.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.css.ts (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/_components/DragGuide/DragGuide.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/constants.ts (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/detail/_components/ContentItem/ContentItem.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/detail/page.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/page.tsx (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/pageStyle.css.ts (1 hunks)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/types.ts (1 hunks)
  • apps/web/src/app/(prompt)/edit/page.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/src/app/(prompt)/edit/page.tsx
✅ Files skipped from review due to trivial changes (2)
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/detail/page.tsx
  • apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/detail/_components/ContentItem/ContentItem.tsx
🔇 Additional comments (2)
apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/types.ts (1)

1-8: 타입 정의가 명확하고 잘 구조화되어 있습니다!

페이지 props와 params에 대한 타입이 명확하게 정의되어 있으며, 재사용성을 고려한 구조입니다.

apps/web/src/app/(prompt)/edit/[agentId]/[postGroupId]/page.tsx (1)

1-6: Next.js 페이지 컴포넌트가 깔끔하게 구현되었습니다!

타입을 잘 활용하고 있으며, props 전달이 명확합니다.

Comment on lines +39 to +42
export const accordionItemStyle = style({
width: '51.2rem',
flex: '0 0 auto',
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

반응형 디자인을 위한 수정이 필요합니다.

width: '51.2rem'와 같은 고정 너비는 작은 화면에서 문제를 일으킬 수 있습니다.

다음과 같이 수정하는 것을 고려해보세요:

export const accordionItemStyle = style({
-  width: '51.2rem',
+  width: '100%',
+  maxWidth: '51.2rem',
  flex: '0 0 auto',
});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const accordionItemStyle = style({
width: '51.2rem',
flex: '0 0 auto',
});
export const accordionItemStyle = style({
width: '100%',
maxWidth: '51.2rem',
flex: '0 0 auto',
});

Comment on lines +8 to +10
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
summary: '경제 기초 지식 1에 대한 요약',
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타임스탬프 생성 방식의 개선이 필요합니다.

상수에서 new Date()를 직접 사용하면 매번 다른 값이 생성되어 일관성 문제가 발생할 수 있습니다.

다음과 같이 수정하는 것을 권장합니다:

+ const BASE_DATE = '2024-02-20T00:00:00Z';

{
  id: 1,
-  createdAt: new Date().toISOString(),
-  updatedAt: new Date().toISOString(),
+  createdAt: BASE_DATE,
+  updatedAt: BASE_DATE,
  // ... 다른 속성들
}

Also applies to: 24-25, 34-35, 44-45, 54-55

size="large"
variant="primary"
leftAddon={<Icon name="checkCalendar" size={20} />}
onClick={() => {}}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

빈 이벤트 핸들러 구현이 필요합니다.

onClickonModify 핸들러가 비어있습니다. 이는 사용자 상호작용에 대한 피드백이 없음을 의미합니다.

각 핸들러에 대한 구체적인 구현이 필요합니다. 임시로 TODO 주석이라도 추가하는 것을 권장합니다.

Also applies to: 89-89, 120-120, 155-155

Comment on lines 76 to 93
<DndControler.Droppable id={POST_STATUS.GENERATED}>
<DndControler.SortableList
items={getItemsByStatus(POST_STATUS.GENERATED).map(
(item) => item.id
)}
>
{getItemsByStatus(POST_STATUS.GENERATED).map((item) => (
<DndControler.Item
key={item.id}
id={item.id}
summary={item.summary}
updatedAt={item.updatedAt}
onRemove={() => handleRemove(item.id)}
onModify={() => {}}
/>
))}
</DndControler.SortableList>
</DndControler.Droppable>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

접근성 개선이 필요합니다.

드래그 앤 드롭 영역에 대한 접근성 속성이 누락되어 있습니다.

다음 접근성 속성들을 추가하는 것을 권장합니다:

  • aria-label
  • role="region"
  • 키보드 네비게이션 지원

예시:

<DndControler.Droppable id={POST_STATUS.GENERATED}>
+ <div
+   role="region"
+   aria-label="생성된 글 목록"
+ >
    <DndControler.SortableList
+     role="list"
      items={getItemsByStatus(POST_STATUS.GENERATED).map(
        (item) => item.id
      )}
    >
      {/* ... */}
    </DndControler.SortableList>
+ </div>
</DndControler.Droppable>

Also applies to: 106-127, 140-163

Comment on lines +178 to +191
onDragEnd={(items) => {
console.log('=== Current Items Status ===');
const itemsByStatus = {
GENERATED: items.filter((item) => item.status === 'GENERATED'),
EDITING: items.filter((item) => item.status === 'EDITING'),
READY_TO_UPLOAD: items.filter(
(item) => item.status === 'READY_TO_UPLOAD'
),
};
console.log('GENERATED:', itemsByStatus.GENERATED);
console.log('EDITING:', itemsByStatus.EDITING);
console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
console.log('========================');
}}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

프로덕션 코드에서 console.log 제거가 필요합니다.

디버깅을 위한 console.log 문은 프로덕션 환경에서 제거되어야 합니다.

다음과 같이 수정하는 것을 권장합니다:

onDragEnd={(items) => {
-  console.log('=== Current Items Status ===');
-  const itemsByStatus = {
-    GENERATED: items.filter((item) => item.status === 'GENERATED'),
-    EDITING: items.filter((item) => item.status === 'EDITING'),
-    READY_TO_UPLOAD: items.filter(
-      (item) => item.status === 'READY_TO_UPLOAD'
-    ),
-  };
-  console.log('GENERATED:', itemsByStatus.GENERATED);
-  console.log('EDITING:', itemsByStatus.EDITING);
-  console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
-  console.log('========================');
+  // TODO: 상태 변경에 따른 처리 로직 구현
}}
📝 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
onDragEnd={(items) => {
console.log('=== Current Items Status ===');
const itemsByStatus = {
GENERATED: items.filter((item) => item.status === 'GENERATED'),
EDITING: items.filter((item) => item.status === 'EDITING'),
READY_TO_UPLOAD: items.filter(
(item) => item.status === 'READY_TO_UPLOAD'
),
};
console.log('GENERATED:', itemsByStatus.GENERATED);
console.log('EDITING:', itemsByStatus.EDITING);
console.log('READY_TO_UPLOAD:', itemsByStatus.READY_TO_UPLOAD);
console.log('========================');
}}
onDragEnd={(items) => {
// TODO: 상태 변경에 따른 처리 로직 구현
}}

Copy link
Member

@kongnayeon kongnayeon 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
Member

Choose a reason for hiding this comment

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

와 이 부분 전체를 SVG로 넣으시려나 했는데 직접 구현하셨군요 👍🏻 👍🏻

);
}

export const DndControler = Object.assign(DndControlerProvider, {
Copy link
Member

Choose a reason for hiding this comment

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

p2;
앗 여기도 파일명 확인 부탁드려요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

수정했어요!

transform,
transition,
isDragging,
} = useSortable({
Copy link
Member

Choose a reason for hiding this comment

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

오 dnd kit에서 sortable을 제공하는군요!!

Copy link
Member

@kongnayeon kongnayeon left a comment

Choose a reason for hiding this comment

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

고생하셨습니다!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature] 결과 수정 페이지 퍼블리싱, DND 모듈 구현
2 participants