Skip to content

Conversation

@yulrang
Copy link
Contributor

@yulrang yulrang commented Nov 18, 2024

🔖 Issue Ticket

#132

✍️ Description

약속 생성하기 기능 API 연결했습니다~!

  • 날짜를 선택하면 폼이 통과되는 문제 해결했습니다!
  • 수정기능은 API가 없어 아직 붙이지 않았습니다~

✅ Checklist

PR

  • Branch Convention 확인

    feat/ 피쳐, fix/ 버그 수정, refactor/ 개선

  • Base Branch 확인
  • 적절한 Label 지정
  • Assignee 및 Reviewer 지정

Test

  • 로컬 작동 확인

Screenshot 2024-11-18 at 09 12 39

Summary by CodeRabbit

  • New Features

    • 새로운 모임 생성 기능 추가: 사용자가 모임을 생성할 수 있는 기능이 도입되었습니다.
    • 모임 생성 시 이미지 업로드 및 날짜/시간 필드 개선.
    • 모임 생성 모달 컴포넌트 추가 및 개선된 사용자 경험 제공.
  • Bug Fixes

    • 날짜 선택 시 이벤트 처리 방식 개선으로 사용자 경험 향상.
  • Chores

    • 컴포넌트 경로 구조 변경으로 코드 정리 및 유지 관리 용이성 향상.

@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

이 변경 사항은 새로운 모임을 생성하는 기능을 추가하는 것으로, createGathering 함수와 useCreateGatheringQuery 후크를 포함합니다. createGathering 함수는 API에 POST 요청을 보내 모임을 생성하며, useCreateGatheringQuery는 React 쿼리 후크를 사용하여 이 작업을 처리합니다. 또한, 여러 컴포넌트의 경로가 변경되고, 파일 업로드 처리 및 날짜/시간 필드의 로직이 개선되었습니다. 전반적으로 모임 생성과 관련된 기능이 강화되었습니다.

Changes

파일 경로 변경 요약
src/_apis/gathering/gathering-detail-apis.ts createGathering 함수 추가, CreateGatheringRequestTypes 임포트 수정
src/_queries/gathering/gathering-detail-queries.ts useCreateGatheringQuery 함수 추가, 관련 임포트 수정
src/app/(crew)/crew/create/page.tsx CreateCrewForm 임포트 경로 수정
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx 파일 업로드 및 dateTime 필드 처리 개선, handleFileChange 함수 추가
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx CreateGatheringModalContainer 컴포넌트 추가, handleSubmit 함수 구현
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/presenter.tsx onSubmit 함수 시그니처 수정
src/app/(crew)/crew/detail/[id]/_components/create-gathering/index.tsx crewId prop 추가, CreateGatheringModalContainer 임포트 경로 수정
src/app/(crew)/crew/detail/[id]/edit/page.tsx CreateCrewForm 임포트 경로 수정
src/app/(crew)/crew/detail/[id]/page.tsx CreateGathering 컴포넌트에 crewId prop 추가
src/components/common/input/date-time-picker/index.tsx handleSelect 함수 수정, onChange 호출 제거

Possibly related PRs

Suggested labels

pages

Suggested reviewers

  • HaeJungg
  • minkyung5x5
  • Rangbyeolang

🐰 새로운 모임을 만들자,
친구들과 함께 즐거운 시간,
파일도 올리고, 날짜도 정해,
모두의 웃음이 가득하길 바라.
함께하는 순간, 소중한 기억,
모임의 시작, 행복한 여정! 🎉


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

@github-actions
Copy link

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

🧹 Outside diff range and nitpick comments (19)
src/_queries/gathering/gathering-detail-queries.ts (1)

13-28: 에러 처리를 개선하면 좋을 것 같습니다.

구현이 전반적으로 잘 되어 있으나, 에러 메시지를 더 구체적으로 처리하면 좋을 것 같습니다.

다음과 같이 에러 처리를 개선하는 것을 제안드립니다:

-    onError: (error) => {
-      toast.error(error.message);
+    onError: (error) => {
+      const errorMessage = error.message || '모임 생성 중 오류가 발생했습니다.';
+      toast.error(errorMessage);
+      console.error('모임 생성 실패:', error);
     },
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/presenter.tsx (2)

5-11: 인터페이스에 JSDoc 문서화를 추가하면 좋을 것 같습니다.

각 프로퍼티의 목적과 사용법을 명확히 이해할 수 있도록 인터페이스에 문서화를 추가하는 것이 좋겠습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 모임 생성 모달의 프로퍼티를 정의하는 인터페이스
+ */
 export interface GatheringDetailModalProps {
+  /** 모달의 표시 여부를 제어 */
   opened: boolean;
+  /** 모달 닫기 핸들러 */
   onClose: () => void;
+  /** 모임 생성 폼 제출 핸들러 */
   onSubmit: (data: CreateGatheringFormTypes) => void;
+  /** 모임 수정 핸들러 */
   onEdit: () => void;
+  /** 모임 데이터 */
   data: CreateGatheringFormTypes;
 }

Line range hint 13-44: 접근성 개선이 필요합니다.

모달 컴포넌트의 접근성을 개선하기 위한 몇 가지 제안사항입니다:

  1. aria-label 또는 aria-labelledby 속성 추가
  2. 모달이 열릴 때 포커스 관리
  3. ESC 키 처리 추가 (현재 Mantine이 처리하고 있을 수 있음)

다음과 같이 수정해보세요:

    <Modal
      opened={opened}
      onClose={onClose}
      centered
      title="약속 만들기"
+     aria-label="약속 만들기 모달"
+     trapFocus
+     returnFocus
      styles={{
        root: { '--modal-size': '520px' },
src/app/(crew)/crew/detail/[id]/_components/create-gathering/index.tsx (2)

37-42: 모달 컨테이너에 필요한 props가 올바르게 전달되었습니다.

새로 추가된 crewId를 포함하여 모든 필수 props가 적절하게 전달되고 있습니다. 하지만 몇 가지 개선사항을 제안드립니다:

  1. 초기값 객체를 컴포넌트 외부로 이동하여 불필요한 재생성을 방지
  2. props 전달 시 가독성을 위해 스프레드 연산자 사용 고려

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

+const INITIAL_GATHERING_VALUE: CreateGatheringFormTypes = {
+  title: '',
+  introduce: '',
+  dateTime: '',
+  location: '',
+  totalCount: 2,
+  imageUrl: null,
+};

export default function CreateGathering({ crewId }: { crewId: number }) {
  const { isAuth } = useAuthStore();
  const router = useRouter();
  const [opened, { open, close }] = useDisclosure(false);

-  const initialValue: CreateGatheringFormTypes = {
-    title: '',
-    introduce: '',
-    dateTime: '',
-    location: '',
-    totalCount: 2,
-    imageUrl: null,
-  };

  return (
    <>
      <Button type="button" className="btn-filled px-4" onClick={handleButtonClick}>
        약속 만들기
      </Button>
      <CreateGatheringModalContainer
-        crewId={crewId}
-        opened={opened}
-        close={close}
-        data={initialValue}
+        {...{
+          crewId,
+          opened,
+          close,
+          data: INITIAL_GATHERING_VALUE
+        }}
      />
    </>
  );
}

Line range hint 15-22: 인증 상태에 따른 처리가 적절합니다.

사용자의 인증 상태에 따라 모달을 열거나 로그인 페이지로 리다이렉트하는 로직이 잘 구현되어 있습니다. 하지만 사용자 경험을 더욱 개선하기 위해 다음 사항을 고려해보세요:

  1. 로그인 후 원래 페이지로 돌아올 수 있도록 리다이렉트 URL 추가
  2. 비로그인 상태일 때 사용자에게 안내 메시지 표시

다음과 같이 수정하는 것을 제안드립니다:

  const handleButtonClick = () => {
    if (isAuth) {
      open();
    } else {
+     // 현재 URL을 state로 전달하여 로그인 후 리다이렉트
+     const returnUrl = encodeURIComponent(window.location.pathname);
-     router.push('/login');
+     router.push(`/login?returnUrl=${returnUrl}`);
+     // TODO: 토스트 메시지 추가
+     // showToast('로그인이 필요한 서비스입니다.');
    }
  };
src/app/(crew)/crew/detail/[id]/edit/page.tsx (3)

Line range hint 16-31: 초기값 설정 로직 개선 필요

현재 initialValue가 하드코딩되어 있으며, API에서 받아온 data를 활용하지 않고 있습니다. 수정 기능의 경우 기존 데이터를 폼에 표시해야 합니다.

-  const initialValue: CreateCrewFormTypes = {
-    title: '',
-    mainCategory: '',
-    subCategory: '',
-    imageUrl:
-      'https://crewcrew.s3.ap-northeast-2.amazonaws.com/crew/0e05d971-15a8-4a32-bf03-80d12cae392e',
-    mainLocation: '',
-    subLocation: '',
-    totalCount: 4,
-    introduce: '',
-  };
+  const initialValue: CreateCrewFormTypes = {
+    title: data.title,
+    mainCategory: data.mainCategory,
+    subCategory: data.subCategory,
+    imageUrl: data.imageUrl,
+    mainLocation: data.mainLocation,
+    subLocation: data.subLocation,
+    totalCount: data.totalCount,
+    introduce: data.introduce,
+  };

Line range hint 33-34: 미구현된 수정 기능에 대한 처리 필요

handleEdit 함수가 구현되지 않았습니다. API가 준비되지 않은 상태라면, 사용자에게 적절한 피드백을 제공해야 합니다.

수정 기능 구현이나 임시 처리 로직 작성을 도와드릴까요?


Line range hint 36-53: 접근성 개선 필요

이미지에 의미 있는 대체 텍스트가 누락되어 있습니다. 스크린 리더 사용자를 위해 적절한 설명을 추가해야 합니다.

-            alt=""
+            alt="크루 수정 페이지 아이콘"
src/app/(crew)/crew/detail/[id]/page.tsx (2)

26-26: Number 변환 중복 개선 필요

params.id를 Number로 변환하는 작업이 중복되어 있습니다. 이미 상단에서 선언된 id 변수를 재사용하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안드립니다:

-<CreateGathering crewId={Number(params.id)} />
+<CreateGathering crewId={id} />

리뷰 섹션 구현이 미완성 상태이며 관련 컴포넌트 준비 필요

리뷰 섹션 관련 파일들이 이미 프로젝트에 존재하지만 실제 구현은 미완성 상태입니다:

  • review-section.tsx에 TODO 주석과 함께 대부분의 기능이 주석 처리되어 있음
  • 필요한 컴포넌트들(RatingDisplay, CrewReviewList)은 이미 준비되어 있으나 실제 데이터 연동 및 구현이 필요한 상태

다음 작업들이 필요합니다:

  • 리뷰 데이터 연동 구현
  • RatingDisplay 컴포넌트 연동
  • CrewReviewList 페이지네이션 구현
  • 전체 리뷰 섹션 UI 완성
🔗 Analysis chain

Line range hint 31-37: 리뷰 섹션 관련 TODO 처리 계획 필요

주석 처리된 리뷰 섹션이 있습니다. 이 기능의 구현 계획과 일정을 명확히 하는 것이 좋을 것 같습니다.

리뷰 섹션 구현을 위한 이슈를 생성하거나 구현 코드를 제안드릴 수 있습니다. 도움이 필요하신가요?

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there's an existing issue for the review section implementation

gh issue list --search "리뷰 섹션" --state open

Length of output: 45


Script:

#!/bin/bash
# Check for any TODO comments related to review section implementation
rg -i "todo.*리뷰" -g "!*.md"

# Check for any CrewReviewSection component references
rg "CrewReviewSection" -g "!*.md"

# Check for any files with "review" in their name under src directory
fd "review" "src"

Length of output: 1181


Script:

#!/bin/bash
# Check the implementation status of review-section component
cat src/app/\(crew\)/crew/detail/\[id\]/_components/review-section.tsx

# Check if there are any related PRs
rg -l "리뷰" .github/

Length of output: 748

src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx (3)

9-14: 이미지 URL 타입 개선 제안

CreateGatheringFormTypes에서 imageUrl 필드가 string | File 타입을 가질 수 있다는 것을 명시적으로 표현하면 좋을 것 같습니다.

export interface CreateGatheringModalContainerProps {
  crewId: number;
  opened: boolean;
  close: () => void;
-  data: CreateGatheringFormTypes;
+  data: Omit<CreateGatheringFormTypes, 'imageUrl'> & {
+    imageUrl: string | File;
+  };
}

42-45: TODO 항목 추적 필요

약속 수정 API가 준비되면 구현이 필요한 부분입니다.

이 TODO 항목을 GitHub 이슈로 생성하여 추적하시겠습니까?


47-63: 로딩 UI 개선 제안

현재 로딩 상태 UI가 너무 단순합니다. 사용자 경험 향상을 위해 다음과 같은 개선을 제안합니다:

if (isPending)
  return (
-   <div className="fixed inset-0 z-10 flex items-center justify-center">
-     <Loader size="sm" />
+   <div className="fixed inset-0 z-10 flex items-center justify-center bg-black/50">
+     <div className="bg-white p-4 rounded-lg shadow-lg">
+       <Loader size="md" />
+       <p className="mt-2 text-sm text-gray-600">모임을 생성하는 중입니다...</p>
+     </div>
    </div>
  );
src/components/common/gathering-card/scheduled-gathering-card/container.tsx (3)

Line range hint 29-67: 더미 데이터의 이메일 주소 처리가 필요합니다.

더미 데이터에 실제와 유사한 이메일 주소가 포함되어 있습니다. 보안상의 이유로 다음과 같이 수정하는 것이 좋습니다:

-      email: '[email protected]',
+      email: '[email protected]',

Line range hint 69-73: TODO 항목들의 이슈화가 필요합니다.

현재 코드에 있는 TODO 코멘트들을 GitHub 이슈로 생성하여 추적하는 것이 좋습니다. 특히 useQuery 관련 부분은 데이터 페칭의 중요한 부분이므로 우선적으로 처리가 필요합니다.

이러한 TODO 항목들을 이슈로 생성하는 것을 도와드릴까요?


Line range hint 74-76: 좋아요 토글 기능의 개선이 필요합니다.

현재 alert를 사용하여 임시로 구현된 좋아요 토글 기능을 실제 API 호출로 대체해야 합니다. 또한 사용자 피드백을 위해 토스트 메시지나 시각적 피드백을 추가하는 것이 좋습니다.

  const handleLikeToggle = useCallback(() => {
-   alert('좋아요 토글됨'); // TODO: 좋아요 토글 로직 구현
+   try {
+     // API 호출 로직
+     showToast('좋아요가 반영되었습니다');
+   } catch (error) {
+     showToast('오류가 발생했습니다. 다시 시도해주세요.');
+   }
  }, []);
src/components/common/gathering-card/container.tsx (1)

Line range hint 52-71: 에러 처리 로직 개선을 제안드립니다.

현재 에러 처리 로직이 컴포넌트 내부에 직접 구현되어 있습니다. 재사용성과 유지보수성을 높이기 위해 다음과 같은 개선을 고려해보세요:

  1. 에러 처리 로직을 별도의 커스텀 훅으로 분리
  2. 에러 메시지를 상수로 관리

다음과 같은 리팩토링을 제안드립니다:

// hooks/useApiErrorHandler.ts
export const useApiErrorHandler = () => {
  const handleError = (error: unknown) => {
    if (error instanceof ApiError) {
      try {
        const errorData = JSON.parse(error.message);
        if (errorData.status === 'NOT_FOUND') {
          toast.error('모임 정보를 찾을 수 없습니다.');
          return;
        }
        toast.error(`Error ${error.status}: ${error.message}`);
      } catch {
        toast.error('데이터 통신에 실패했습니다.');
      }
    }
  };
  return { handleError };
};

컴포넌트에서는 다음과 같이 사용할 수 있습니다:

const { handleError } = useApiErrorHandler();
useEffect(() => {
  if (error) {
    handleError(error);
  }
}, [error]);
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx (2)

165-167: 날짜 데이터 처리 개선이 확인되었습니다.

날짜 객체를 직접 전달하도록 변경한 것은 좋은 개선입니다. 데이터 변환 단계를 줄여 코드가 더 명확해졌습니다.

다만, 타입 안전성을 위해 date 매개변수의 타입을 명시적으로 지정하는 것을 고려해보세요:

-                onChange={(date) => {
+                onChange={(date: Date) => {

Line range hint 84-94: 상수 값 분리 제안

파일 업로드 관련 제한사항을 상수로 분리하면 유지보수성이 향상될 것 같습니다:

const FILE_SIZE_LIMIT = 5 * 1024 * 1024; // 5MB
const ACCEPTED_FILE_TYPES = ['image/jpeg', 'image/jpg', 'image/png'] as const;

이렇게 분리된 상수는 다음과 같이 사용할 수 있습니다:

                validate: {
                  fileSize: (file) =>
                    file && file instanceof File
-                     ? file.size <= 5242880 || '파일 크기는 5MB 이하여야 합니다.'
+                     ? file.size <= FILE_SIZE_LIMIT || '파일 크기는 5MB 이하여야 합니다.'
                      : true,
                  fileType: (file) =>
                    file && file instanceof File
-                     ? ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type) ||
+                     ? ACCEPTED_FILE_TYPES.includes(file.type as typeof ACCEPTED_FILE_TYPES[number]) ||
                        'JPG, PNG 파일만 업로드 가능합니다.'
                      : true,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ab16aad and db4a1c0.

📒 Files selected for processing (13)
  • src/_apis/gathering/gathering-detail-apis.ts (2 hunks)
  • src/_queries/gathering/gathering-detail-queries.ts (1 hunks)
  • src/app/(crew)/crew/_components/create-gathering-modal/container.tsx (0 hunks)
  • src/app/(crew)/crew/create/page.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/presenter.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/index.tsx (2 hunks)
  • src/app/(crew)/crew/detail/[id]/edit/page.tsx (1 hunks)
  • src/app/(crew)/crew/detail/[id]/page.tsx (1 hunks)
  • src/components/common/gathering-card/container.tsx (1 hunks)
  • src/components/common/gathering-card/scheduled-gathering-card/container.tsx (1 hunks)
  • src/components/common/input/date-time-picker/index.tsx (0 hunks)
💤 Files with no reviewable changes (2)
  • src/app/(crew)/crew/_components/create-gathering-modal/container.tsx
  • src/components/common/input/date-time-picker/index.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/app/(crew)/crew/create/page.tsx
🔇 Additional comments (9)
src/_queries/gathering/gathering-detail-queries.ts (1)

1-4: 임포트 구문이 적절히 구성되어 있습니다.

필요한 모든 의존성이 올바르게 임포트되어 있으며, 각 임포트의 용도가 명확합니다.

src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/presenter.tsx (1)

2-3: 임포트 경로가 적절히 구성되었습니다!

절대 경로를 사용하여 컴포넌트와 타입을 임포트하는 방식이 일관성 있게 적용되었습니다.

src/app/(crew)/crew/detail/[id]/_components/create-gathering/index.tsx (2)

6-6: 임포트 경로가 적절히 업데이트되었습니다.

컴포넌트의 새로운 위치를 반영하여 임포트 경로가 정확하게 수정되었습니다.


10-10: 타입 정의가 명확하게 되어있습니다.

crewId prop이 number 타입으로 명시적으로 정의되어 있어 타입 안정성이 보장됩니다.

src/app/(crew)/crew/detail/[id]/edit/page.tsx (1)

6-6: 컴포넌트 경로 변경이 일관성 있게 적용되었는지 확인 필요

컴포넌트 경로가 변경되었습니다. 이 변경이 다른 파일들에도 올바르게 반영되었는지 확인이 필요합니다.

✅ Verification successful

Based on the search results, I can generate the final response as both files are using the new import path consistently (@/src/app/(crew)/crew/create/_components/create-crew-form). There's no need for additional verification.

컴포넌트 경로가 일관되게 적용되어 있습니다

CreateCrewForm 컴포넌트의 import 경로가 모든 사용처에서 새로운 경로로 올바르게 적용되어 있음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: CreateCrewForm 컴포넌트의 import 경로 사용 현황 확인

# 이전 경로 사용 여부 확인
rg "@/src/app/\(crew\)/crew/_components/create-crew-form"

# 새로운 경로 사용 여부 확인
rg "@/src/app/\(crew\)/crew/create/_components/create-crew-form"

Length of output: 384

src/_apis/gathering/gathering-detail-apis.ts (1)

2-2: 타입 임포트가 적절히 추가되었습니다!

CreateGatheringRequestTypes 타입이 새로운 함수와 함께 잘 통합되었습니다.

src/components/common/gathering-card/scheduled-gathering-card/container.tsx (1)

2-2: 임포트 경로 변경이 적절합니다!

절대 경로를 사용하여 컴포넌트를 임포트하는 방식으로 변경한 것이 좋습니다. Next.js의 라우팅 구조와도 잘 맞습니다.

src/components/common/gathering-card/container.tsx (2)

Line range hint 1-99: 전반적으로 잘 구현된 컴포넌트입니다.

컴포넌트의 구조와 기능이 잘 구현되어 있습니다:

  • 상태 관리가 깔끔하게 되어 있습니다
  • 날짜 처리 로직이 명확합니다
  • Presenter 패턴을 잘 활용하고 있습니다

8-8: 새로운 import 경로가 올바르게 작동하는지 확인이 필요합니다.

새로운 라우팅 구조로 변경된 import 경로가 모든 상황에서 올바르게 동작하는지 확인해주세요.

✅ Verification successful

새로운 import 경로가 정상적으로 작동하는 것을 확인했습니다.

  • 새 경로 @/src/app/(crew)/crew/detail/[id]/_components/gathering-detail-modal/container.tsx에 컴포넌트가 올바르게 구현되어 있습니다.
  • 모든 import 구문이 새로운 경로로 일관되게 업데이트되었습니다.
  • 순환 참조 문제도 발견되지 않았습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the new import path exists and is used consistently

# Check if the new path exists
fd "container.tsx" "src/app/(crew)/crew/detail/[id]/_components/gathering-detail-modal"

# Check for any remaining old import paths
rg "import.*GatheringDetailModalContainer.*crew/_components/gathering-detail-modal" --type ts

Length of output: 264


Script:

#!/bin/bash
# Check all imports of GatheringDetailModalContainer to ensure consistency
rg "import.*GatheringDetailModalContainer" --type ts -A 1

# Check the actual implementation exists in the new location
cat "src/app/(crew)/crew/detail/[id]/_components/gathering-detail-modal/container.tsx"

# Check for any potential circular dependencies
rg "gathering-card" "src/app/(crew)/crew/detail/[id]/_components/gathering-detail-modal/container.tsx"

Length of output: 2981

queryKey: ['gatheringList', crewId],
refetchType: 'all',
});
toast.success('크루가 생성되었습니다.');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

성공 메시지의 용어를 수정해야 합니다.

성공 메시지에서 "크루가 생성되었습니다"라고 되어 있는데, PR의 목적에 따르면 이는 "모임"을 생성하는 기능입니다.

다음과 같이 수정하는 것을 제안드립니다:

-      toast.success('크루가 생성되었습니다.');
+      toast.success('모임이 생성되었습니다.');
📝 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
toast.success('크루가 생성되었습니다.');
toast.success('모임이 생성되었습니다.');

Comment on lines +56 to +69
export async function createGathering(id: number, data: CreateGatheringRequestTypes) {
try {
await fetchApi(`/api/crews/${id}/gatherings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // Include authentication credentials
body: JSON.stringify(data),
});
} catch (error) {
throw error;
}
}
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 구현에 대한 몇 가지 개선사항이 있습니다.

다음 사항들을 개선하면 좋을 것 같습니다:

  1. 에러 처리가 너무 일반적입니다. 구체적인 에러 케이스를 처리해주세요.
  2. 함수의 반환 타입이 명시되어 있지 않습니다.
  3. id 매개변수의 이름이 모호합니다. crewId로 변경하면 좋겠습니다.
  4. 입력값 유효성 검사가 없습니다.

다음과 같이 수정하는 것을 제안드립니다:

-export async function createGathering(id: number, data: CreateGatheringRequestTypes) {
+export async function createGathering(
+  crewId: number,
+  data: CreateGatheringRequestTypes
+): Promise<void> {
+  if (!crewId || crewId <= 0) {
+    throw new Error('유효하지 않은 크루 ID입니다.');
+  }
+
   try {
-    await fetchApi(`/api/crews/${id}/gatherings`, {
+    await fetchApi(`/api/crews/${crewId}/gatherings`, {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
       },
       credentials: 'include',
       body: JSON.stringify(data),
     });
   } catch (error) {
-    throw error;
+    if (error instanceof Error) {
+      throw new Error(`모임 생성 중 오류 발생: ${error.message}`);
+    }
+    throw new 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 createGathering(id: number, data: CreateGatheringRequestTypes) {
try {
await fetchApi(`/api/crews/${id}/gatherings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // Include authentication credentials
body: JSON.stringify(data),
});
} catch (error) {
throw error;
}
}
export async function createGathering(
crewId: number,
data: CreateGatheringRequestTypes
): Promise<void> {
if (!crewId || crewId <= 0) {
throw new Error('유효하지 않은 크루 ID입니다.');
}
try {
await fetchApi(`/api/crews/${crewId}/gatherings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify(data),
});
} catch (error) {
if (error instanceof Error) {
throw new Error(`모임 생성 중 오류 발생: ${error.message}`);
}
throw new Error('알 수 없는 오류가 발생했습니다.');
}
}

Comment on lines 16 to 22
export default function CreateGatheringModalContainer({
crewId,
opened,
close,
data,
}: CreateGatheringModalContainerProps) {
const { isPending, mutate } = useCreateGatheringQuery(crewId);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리 추가 필요

useCreateGatheringQuery의 에러 상태를 처리하는 로직이 없습니다. 사용자에게 적절한 에러 메시지를 표시하는 것이 좋을 것 같습니다.

- const { isPending, mutate } = useCreateGatheringQuery(crewId);
+ const { isPending, error, mutate } = useCreateGatheringQuery(crewId);
+
+ useEffect(() => {
+   if (error) {
+     notifications.show({
+       title: '오류 발생',
+       message: '모임을 생성하는 중 문제가 발생했습니다.',
+       color: 'red',
+     });
+   }
+ }, [error]);

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

Comment on lines 24 to 41
const handleSubmit = async (createdData: CreateGatheringFormTypes) => {
let newImageUrl = createdData.imageUrl as string;
if (createdData.imageUrl instanceof File) {
const imgResponse = await getImageUrl(createdData.imageUrl, 'CREW');
newImageUrl = imgResponse?.imageUrl as string;
}
const newData: CreateGatheringRequestTypes = {
title: createdData.title,
imageUrl: newImageUrl ?? '',
dateTime: createdData.dateTime,
location: createdData.location,
totalCount: createdData.totalCount,
introduce: createdData.introduce,
};

mutate(newData);
close();
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

비동기 처리 및 에러 핸들링 개선 필요

  1. mutate 호출 후 즉시 모달을 닫는 것은 사용자 경험상 좋지 않을 수 있습니다.
  2. 이미지 업로드 실패 시 에러 처리가 없습니다.
const handleSubmit = async (createdData: CreateGatheringFormTypes) => {
  try {
    let newImageUrl = createdData.imageUrl as string;
    if (createdData.imageUrl instanceof File) {
      const imgResponse = await getImageUrl(createdData.imageUrl, 'CREW');
+     if (!imgResponse?.imageUrl) {
+       throw new Error('이미지 업로드 실패');
+     }
      newImageUrl = imgResponse?.imageUrl as string;
    }
    const newData: CreateGatheringRequestTypes = {
      title: createdData.title,
      imageUrl: newImageUrl ?? '',
      dateTime: createdData.dateTime,
      location: createdData.location,
      totalCount: createdData.totalCount,
      introduce: createdData.introduce,
    };

-   mutate(newData);
-   close();
+   await mutate(newData);
+   close();
+  } catch (error) {
+    notifications.show({
+      title: '오류 발생',
+      message: '모임 생성에 실패했습니다. 다시 시도해주세요.',
+      color: 'red',
+    });
+  }
};
📝 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 handleSubmit = async (createdData: CreateGatheringFormTypes) => {
let newImageUrl = createdData.imageUrl as string;
if (createdData.imageUrl instanceof File) {
const imgResponse = await getImageUrl(createdData.imageUrl, 'CREW');
newImageUrl = imgResponse?.imageUrl as string;
}
const newData: CreateGatheringRequestTypes = {
title: createdData.title,
imageUrl: newImageUrl ?? '',
dateTime: createdData.dateTime,
location: createdData.location,
totalCount: createdData.totalCount,
introduce: createdData.introduce,
};
mutate(newData);
close();
};
const handleSubmit = async (createdData: CreateGatheringFormTypes) => {
try {
let newImageUrl = createdData.imageUrl as string;
if (createdData.imageUrl instanceof File) {
const imgResponse = await getImageUrl(createdData.imageUrl, 'CREW');
if (!imgResponse?.imageUrl) {
throw new Error('이미지 업로드 실패');
}
newImageUrl = imgResponse?.imageUrl as string;
}
const newData: CreateGatheringRequestTypes = {
title: createdData.title,
imageUrl: newImageUrl ?? '',
dateTime: createdData.dateTime,
location: createdData.location,
totalCount: createdData.totalCount,
introduce: createdData.introduce,
};
await mutate(newData);
close();
} catch (error) {
notifications.show({
title: '오류 발생',
message: '모임 생성에 실패했습니다. 다시 시도해주세요.',
color: 'red',
});
}
};

@github-actions
Copy link

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

🧹 Outside diff range and nitpick comments (1)
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx (1)

177-179: 날짜 유효성 검사를 추가하면 좋을 것 같습니다.

현재는 기본적인 필수값 검사만 되어있습니다. 과거 날짜 선택 방지나 유효한 날짜 범위 설정 등의 추가적인 유효성 검사를 고려해보시면 좋을 것 같습니다.

예시 코드입니다:

rules={{
  required: '날짜와 시간을 선택해주세요.',
  validate: {
    isFuture: (date) =>
      date > new Date() || '과거 날짜는 선택할 수 없습니다.',
    isWithinRange: (date) =>
      date < new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) ||
      '최대 30일 이내의 날짜만 선택 가능합니다.',
  },
}}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between db4a1c0 and 648d0de.

📒 Files selected for processing (2)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx (4 hunks)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-modal/container.tsx
🔇 Additional comments (1)
src/app/(crew)/crew/detail/[id]/_components/create-gathering/create-gathering-form/index.tsx (1)

42-50: 이미지 업로드 처리가 잘 구현되었습니다!

비동기 처리와 타입 체크가 적절하게 구현되어 있습니다. 파일 업로드 실패 시 빈 문자열을 반환하는 처리도 안전합니다.

Comment on lines +117 to 119
handleFileChange(newValue, field.onChange);
field.onChange(newValue);
trigger('imageUrl');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

onChange 핸들러의 중복 호출 문제를 수정해주세요.

현재 코드에서는 handleFileChangefield.onChange가 연속적으로 호출되어 잠재적인 상태 불일치 문제가 발생할 수 있습니다.

다음과 같이 수정하는 것을 추천드립니다:

-handleFileChange(newValue, field.onChange);
-field.onChange(newValue);
-trigger('imageUrl');
+handleFileChange(newValue, (value) => {
+  field.onChange(value);
+  trigger('imageUrl');
+});
📝 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
handleFileChange(newValue, field.onChange);
field.onChange(newValue);
trigger('imageUrl');
handleFileChange(newValue, (value) => {
field.onChange(value);
trigger('imageUrl');
});

Copy link
Contributor

@minkyung5x5 minkyung5x5 left a comment

Choose a reason for hiding this comment

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

수고많으셨습니다!!!!

@github-actions
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants