Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
24 changes: 24 additions & 0 deletions src/_apis/crew/my-crew-creation-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fetchApi } from '@/src/utils/api';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export async function getMyCrewCreationList(pageable: PageableTypes) {
const { page, size, sort = ['string'] } = pageable;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

정렬 기본값 수정이 필요합니다

코드베이스 분석 결과, 다음과 같은 문제점들이 확인되었습니다:

  • ['string']이라는 기본값이 여러 crew API 호출에서 동일하게 사용되고 있습니다
  • find-crew 컴포넌트에서는 'latest'를 기본 정렬값으로 사용하고 있습니다
  • ConditionTypes에서는 sortType'LATEST' | 'POPULAR' 타입으로 정의되어 있습니다

개선 제안:

  • sort 기본값을 ['createdAt,desc']와 같이 의미 있는 값으로 변경
  • PageableTypes 인터페이스의 sort 타입을 더 구체적으로 정의하여 유효한 정렬 옵션만 허용하도록 수정
🔗 Analysis chain

sort 매개변수의 기본값을 검토해주세요.

sort의 기본값으로 설정된 ['string']이 의미 있는 정렬 기준으로 보이지 않습니다. 다음과 같은 개선을 제안드립니다:

  • 실제 정렬 기준(예: 'createdAt', 'name' 등)을 기본값으로 설정
  • 정렬 기준에 대한 타입을 명시적으로 정의
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 백엔드 API에서 지원하는 정렬 기준 확인

# API 문서나 관련 코드에서 정렬 옵션 검색
rg -t ts -t js "sort.*=.*\[.*\].*crews" 

Length of output: 41


Script:

#!/bin/bash
# Let's check the file content and its imports to understand the context better
cat src/_apis/crew/my-crew-creation-list.ts

# Also search for any pageable interface or type definitions
rg -t ts "interface.*Pageable" -A 5
rg -t ts "type.*Pageable" -A 5

# Search for any usage of sort parameter in crew-related files
rg -t ts "sort.*crews?" src/_apis/crew/

Length of output: 1081


Script:

#!/bin/bash
# Let's check if there are any other crew list API calls that might show the sort parameter usage
rg -t ts "/api/crews.*sort" -B 2 -A 2

# Check for any constants or enums that might define sort options
rg -t ts "enum.*Sort" -A 5
rg -t ts "const.*sort.*=" -A 5

# Check the crew-card type file completely to understand the context better
cat src/types/crew-card.d.ts

Length of output: 4722


try {
const response = await fetchApi<MyCrewListResponse>(
`/api/crews/hosted?page=${page}&size=${size}&sort=${sort}`,
{
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

쿼리 파라미터의 보안 처리가 필요합니다.

URL 쿼리 파라미터에 대한 인코딩이 누락되어 있습니다. 잠재적인 보안 위험을 방지하기 위해 encodeURIComponent를 사용하여 파라미터를 인코딩해주세요.

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

-      `/api/crews/hosted?page=${page}&size=${size}&sort=${sort}`,
+      `/api/crews/hosted?page=${encodeURIComponent(page)}&size=${encodeURIComponent(size)}&sort=${encodeURIComponent(sort.join(','))}`,

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

method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);
return response;
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
return undefined;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리 로직을 개선해주세요.

현재 에러 처리에 몇 가지 개선이 필요해 보입니다:

  1. console.error는 프로덕션 환경에서 적절하지 않습니다
  2. 에러 발생 시 undefined를 반환하면 타입 안전성이 저하됩니다
  3. 호출자에게 구체적인 에러 정보가 전달되지 않습니다

다음과 같은 개선된 구현을 제안드립니다:

-  } catch (error) {
-    // eslint-disable-next-line no-console
-    console.error(error);
-    return undefined;
+  } catch (error: unknown) {
+    const errorMessage = error instanceof Error ? error.message : '크루 목록을 불러오는 중 오류가 발생했습니다';
+    throw new Error(errorMessage);
   }
📝 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
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
return undefined;
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : '크루 목록을 불러오는 중 오류가 발생했습니다';
throw new Error(errorMessage);
}

}
24 changes: 24 additions & 0 deletions src/_apis/crew/my-crew-participation-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fetchApi } from '@/src/utils/api';
import { MyCrewListResponse, PageableTypes } from '@/src/types/crew-card';

export async function getMyCrewParticipationList(pageable: PageableTypes) {
const { page, size, sort = ['string'] } = pageable;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

sort 기본값 처리 방식 개선이 필요합니다.

sort 파라미터의 기본값이 ['string']으로 설정되어 있는데, 이는 실제 정렬에 적용하기에 적절하지 않은 값으로 보입니다. 유효한 정렬 기준을 기본값으로 설정하는 것이 좋겠습니다.

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

-  const { page, size, sort = ['string'] } = pageable;
+  const { page, size, sort = ['createdAt,desc'] } = pageable;
📝 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 getMyCrewParticipationList(pageable: PageableTypes) {
const { page, size, sort = ['string'] } = pageable;
export async function getMyCrewParticipationList(pageable: PageableTypes) {
const { page, size, sort = ['createdAt,desc'] } = pageable;


try {
const response = await fetchApi<MyCrewListResponse>(
`/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);
return response;
} catch (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

에러 처리 개선이 필요합니다.

현재 구현은 모든 에러를 콘솔에 출력하고 undefined를 반환하고 있습니다. 이는 다음과 같은 문제가 있습니다:

  1. 에러 타입에 따른 구체적인 처리가 없습니다
  2. 사용자에게 적절한 에러 메시지를 전달할 수 없습니다

다음과 같이 개선을 제안드립니다:

  try {
    const response = await fetchApi<MyCrewListResponse>(
      `/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
        credentials: 'include',
      },
    );
    return response;
  } catch (error) {
-   // eslint-disable-next-line no-console
-   console.error(error);
-   return undefined;
+   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
try {
const response = await fetchApi<MyCrewListResponse>(
`/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // 인증 정보를 요청에 포함
},
);
return response;
} catch (error) {
try {
const response = await fetchApi<MyCrewListResponse>(
`/api/crews/joined?page=${page}&size=${size}&sort=${sort}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
},
);
return response;
} catch (error) {
if (error instanceof Error) {
throw new Error(`크루 참여 목록을 가져오는데 실패했습니다: ${error.message}`);
}
throw new Error('알 수 없는 에러가 발생했습니다');
}

// eslint-disable-next-line no-console
console.error(error);
return undefined;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { UseInfiniteQueryOptions } from '@tanstack/react-query';
import { ConditionTypes, MainCrewListResponse, PageableTypes } from '@/src/types/crew-card';
import { getCrewList } from '../_apis/crew/get-crew-list';
import { getCrewList } from '@/src/_apis/crew/crew-list';
import { ConditionTypes, MainCrewListResponse } from '@/src/types/crew-card';

export function useGetCrewListQuery(condition: ConditionTypes) {
return {
Expand All @@ -15,7 +14,7 @@ export function useGetCrewListQuery(condition: ConditionTypes) {
getCrewList(condition, { page: pageParam, size: 6, sort: [condition.sortType] }).then(
(response) => {
if (response === undefined) {
throw new Error('Response is null');
throw new Error('Response is undefined');
}
return response;
},
Expand Down
17 changes: 17 additions & 0 deletions src/_queries/crew/my-crew-creation-list-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getMyCrewCreationList } from '@/src/_apis/crew/my-crew-creation-list';
import { MyCrewListResponse } from '@/src/types/crew-card';

export function useGetMyCrewCreationQuery() {
return {
queryKey: ['my-crew-creation'],
queryFn: ({ pageParam = 0 }) =>
getMyCrewCreationList({ page: pageParam, size: 6, sort: ['string'] }).then((response) => {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

sort 파라미터 값을 검토해주세요.

현재 sort 파라미터가 ['string']으로 하드코딩되어 있습니다. 이는 실제 정렬 로직에 문제를 일으킬 수 있습니다.

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

-      getMyCrewCreationList({ page: pageParam, size: 6, sort: ['string'] }).then((response) => {
+      getMyCrewCreationList({ page: pageParam, size: 6, sort: ['createdAt,DESC'] }).then((response) => {
📝 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
getMyCrewCreationList({ page: pageParam, size: 6, sort: ['string'] }).then((response) => {
getMyCrewCreationList({ page: pageParam, size: 6, sort: ['createdAt,DESC'] }).then((response) => {

if (response === undefined) {
throw new Error('Response is undefined');
}
return response;
}),
getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) =>
lastPage.hasNext ? allPages.length : undefined,
};
}
19 changes: 19 additions & 0 deletions src/_queries/crew/my-crew-participation-list-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getMyCrewParticipationList } from '@/src/_apis/crew/my-crew-participation-list';
import { MyCrewListResponse } from '@/src/types/crew-card';

export function useGetMyCrewParticipationQuery() {
return {
queryKey: ['my-crew-participation'],
queryFn: ({ pageParam = 0 }) =>
getMyCrewParticipationList({ page: pageParam, size: 6, sort: ['string'] }).then(
(response) => {
if (response === undefined) {
throw new Error('Response is undefined');
}
return response;
},
),
getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) =>
lastPage.hasNext ? allPages.length : undefined,
};
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

쿼리 구현에 대한 몇 가지 개선사항이 있습니다.

다음 사항들을 검토해주시기 바랍니다:

  1. sort 파라미터가 ['string']으로 하드코딩되어 있는데, 이는 올바른 정렬 기준이 아닌 것 같습니다.
  2. 페이지 크기(size: 6)가 하드코딩되어 있어 재사용성이 제한됩니다.
  3. 에러 처리가 너무 일반적입니다.

다음과 같이 개선하는 것을 제안드립니다:

-export function useGetMyCrewParticipationQuery() {
+export function useGetMyCrewParticipationQuery({
+  pageSize = 6,
+  sortOrder = ['createdAt,desc']
+}: {
+  pageSize?: number;
+  sortOrder?: string[];
+} = {}) {
   return {
     queryKey: ['my-crew-participation'],
     queryFn: ({ pageParam = 0 }) =>
-      getMyCrewParticipationList({ page: pageParam, size: 6, sort: ['string'] }).then(
+      getMyCrewParticipationList({ page: pageParam, size: pageSize, sort: sortOrder }).then(
         (response) => {
           if (response === undefined) {
-            throw new Error('Response is undefined');
+            throw new Error('크루 참여 목록을 가져오는데 실패했습니다.');
           }
           return response;
         },
       ),
     getNextPageParam: (lastPage: MyCrewListResponse, allPages: MyCrewListResponse[]) =>
       lastPage.hasNext ? allPages.length : undefined,
   };
 }

추가로, 타입 안전성을 위해 API 응답 타입을 명시적으로 지정하는 것이 좋습니다:

queryFn: ({ pageParam = 0 }): Promise<MyCrewListResponse> => {

19 changes: 19 additions & 0 deletions src/app/(crew)/my-crew/creation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import { useGetMyCrewCreationQuery } from '@/src/_queries/crew/my-crew-creation-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';

export default function MyCrewParticipationPage() {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

컴포넌트 이름과 디렉토리 위치가 일치하지 않습니다.

현재 컴포넌트 이름은 MyCrewParticipationPage이지만 creation 디렉토리에 위치해 있습니다. 컴포넌트의 실제 목적에 맞게 이름을 변경하는 것이 좋겠습니다.

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

-export default function MyCrewParticipationPage() {
+export default function MyCrewCreationPage() {
📝 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 default function MyCrewParticipationPage() {
export default function MyCrewCreationPage() {

const { data, ref, isFetchingNextPage } = useInfiniteScroll(useGetMyCrewCreationQuery());
return (
<div>
<CrewCardList
inWhere="my-crew"
data={data ?? { pages: [], pageParams: [] }}
ref={ref}
isFetchingNextPage={isFetchingNextPage}
/>
</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

에러 처리와 로딩 상태 관리가 필요합니다.

다음 개선사항들을 고려해주세요:

  1. 쿼리 실패 시 에러 처리
  2. 초기 로딩 상태 처리
  3. 데이터 타입 안전성 강화

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

 export default function MyCrewParticipationPage() {
-  const { data, ref, isFetchingNextPage } = useInfiniteScroll(useGetMyCrewCreationQuery());
+  const { data, ref, isFetchingNextPage, isError, error, isLoading } = useInfiniteScroll(useGetMyCrewCreationQuery());
+
+  if (isError) {
+    return <div>에러가 발생했습니다: {error.message}</div>;
+  }
+
+  if (isLoading) {
+    return <div>로딩 중...</div>;
+  }

   return (
     <div>
       <CrewCardList
         inWhere="my-crew"
         data={data ?? { pages: [], pageParams: [] }}
         ref={ref}
         isFetchingNextPage={isFetchingNextPage}
       />
     </div>
   );
 }

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

41 changes: 41 additions & 0 deletions src/app/(crew)/my-crew/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client';

import { ReactNode, useEffect, useState } from 'react';
import { usePathname, useRouter } from 'next/navigation';
import Tabs from '@/src/components/common/tab';

export default function MyCrewLayout({ children }: { children: ReactNode }) {
const router = useRouter();
const currentPath = usePathname();
const myCrewTabs = [
{ label: '내가 참여한 크루', id: 'joined-crew', route: '/my-crew/participation' },
{ label: '내가 만든 크루', id: 'made-crew', route: '/my-crew/creation' },
];
const [currentTab, setCurrentTab] = useState(myCrewTabs[0].id);

const handleTabClick = (id: string) => {
const targetRoute = myCrewTabs.find((tab) => tab.id === id)?.route;
if (targetRoute) router.push(targetRoute);
};
Comment on lines +16 to +19
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리 개선이 필요합니다

targetRoute가 없는 경우에 대한 처리가 누락되어 있습니다. 사용자에게 적절한 피드백을 제공하는 것이 좋습니다.

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

 const handleTabClick = (id: string) => {
   const targetRoute = myCrewTabs.find((tab) => tab.id === id)?.route;
-  if (targetRoute) router.push(targetRoute);
+  if (targetRoute) {
+    router.push(targetRoute);
+  } else {
+    console.error(`탭 ID ${id}에 해당하는 경로를 찾을 수 없습니다.`);
+    // TODO: 사용자에게 에러 메시지 표시
+  }
 };

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


useEffect(() => {
const activeTabId = myCrewTabs.find((tab) => tab.route === currentPath)?.id;
if (activeTabId) setCurrentTab(activeTabId);
}, [currentPath]);

return (
<div className="py-8 md:py-12.5">
<div className="px-3 md:px-8 lg:px-11.5">
<Tabs
variant="default"
tabs={myCrewTabs}
activeTab={currentTab}
onTabClick={(id) => {
handleTabClick(id);
}}
/>
</div>
<div className="mt-8 px-3 md:px-8 lg:px-11.5">{children}</div>
</div>
);
}
43 changes: 2 additions & 41 deletions src/app/(crew)/my-crew/page.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,5 @@
'use client';

import { useState } from 'react';
import { useGetCrewListQuery } from '@/src/_queries/crew-queries';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import Tabs from '@/src/components/common/tab';
import { MyCrewListResponse } from '@/src/types/crew-card';
import { redirect } from 'next/navigation';

export default function MyCrewPage() {
const myPageTabs = [
{ label: '내가 참여한 크루', id: 'joined-crew' },
{ label: '내가 만든 크루', id: 'made-crew' },
];
const [currentTab, setCurrentTab] = useState(myPageTabs[0].id);

// TODO: fetchCrewData 함수를 사용하여 데이터를 불러오기 : 파라미터 수정 필요
// TODO: 리스트와는 다른 데이터를 사용해야해서 우선 주석처리 했습니다.
// const { data, ref, isFetchingNextPage } =
// useInfiniteScroll<MyCrewListResponse>(useGetCrewListQuery());

return (
<div className="py-8 md:py-12.5">
<div className="px-3 md:px-8 lg:px-11.5">
<Tabs
variant="default"
tabs={myPageTabs}
activeTab={currentTab}
onTabClick={(id) => {
setCurrentTab(id);
}}
/>
</div>
<div className="mt-8 px-3 md:px-8 lg:px-11.5">
{/* <CrewCardList
inWhere="my-crew"
data={data}
ref={ref}
isFetchingNextPage={isFetchingNextPage}
/> */}
</div>
</div>
);
redirect('/my-crew/participation');
}
19 changes: 19 additions & 0 deletions src/app/(crew)/my-crew/participation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import { useGetMyCrewParticipationQuery } from '@/src/_queries/crew/my-crew-participation-list-query';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';

export default function MyCrewParticipationPage() {
const { data, ref, isFetchingNextPage } = useInfiniteScroll(useGetMyCrewParticipationQuery());
return (
<div>
<CrewCardList
inWhere="my-crew"
data={data ?? { pages: [], pageParams: [] }}
ref={ref}
isFetchingNextPage={isFetchingNextPage}
/>
</div>
);
}
2 changes: 1 addition & 1 deletion src/app/(crew)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCrewList } from '@/src/_apis/crew/get-crew-list';
import { getCrewList } from '@/src/_apis/crew/crew-list';
import FindCrew from '../_components/find-crew/find-crew';

export default async function HomePage() {
Expand Down
2 changes: 1 addition & 1 deletion src/app/_components/find-crew/find-crew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react';
import Image from 'next/image';
import { Divider, TextInput } from '@mantine/core';
import { InfiniteData } from '@tanstack/react-query';
import { useGetCrewListQuery } from '@/src/_queries/crew-queries';
import { useGetCrewListQuery } from '@/src/_queries/crew/crew-list-queries';
import regionData from '@/src/data/region.json';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import CategoryContainer from '@/src/app/_components/category/category-container';
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/crew-list/crew-card-list.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { InfiniteData } from '@tanstack/react-query';
import { useGetCrewListQuery } from '@/src/_queries/crew-queries';
import { useGetCrewListQuery } from '@/src/_queries/crew/crew-list-queries';
import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll';
import ClientProvider from '@/src/components/client-provider';
import { MainCrewListResponse } from '@/src/types/crew-card';
Expand Down
18 changes: 5 additions & 13 deletions src/components/common/crew-list/crew-card-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,21 @@ import {
import CrewCard from './crew-card';

// CrewCardListProps 타입을 구분하여 정의
interface MainCrewCardListProps {
data: InfiniteData<MainCrewListResponse | undefined>;
interface CrewCardListProps {
data: InfiniteData<MainCrewListResponse | MyCrewListResponse | undefined>;
isFetchingNextPage: boolean;
inWhere?: undefined;
inWhere?: 'my-crew' | 'main-crew';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

타입 안전성 개선이 필요합니다.

inWhere 프로퍼티에서 undefined 타입이 제거되었는데, 이는 상위 컴포넌트에서 해당 prop을 필수로 전달해야 함을 의미합니다. 기존 코드와의 호환성 문제가 발생할 수 있습니다.

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

interface CrewCardListProps {
  data: InfiniteData<MainCrewListResponse | MyCrewListResponse | undefined>;
  isFetchingNextPage: boolean;
-  inWhere?: 'my-crew' | 'main-crew';
+  inWhere: 'my-crew' | 'main-crew' | undefined;
}

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

}

interface MyCrewCardListProps {
data: InfiniteData<MyCrewListResponse>;
isFetchingNextPage: boolean;
inWhere: 'my-crew';
}

// 유니온 타입으로 정의
type CrewCardListProps = MainCrewCardListProps | MyCrewCardListProps;

function CrewCardList(
{ data, isFetchingNextPage, inWhere }: CrewCardListProps,
ref: React.Ref<HTMLDivElement>,
) {
const crewDataList =
(inWhere === 'my-crew'
? data?.pages.flatMap((page) => page?.data as MyCrewList[])
? data?.pages.flatMap((page) => page?.content as MyCrewList[])
: data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? [];

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 가드를 추가하여 런타임 안전성을 개선해주세요.

현재 타입 단언(type assertion)을 사용하고 있는데, 이는 런타임에서 타입 안전성을 보장하지 않습니다.

다음과 같이 타입 가드를 추가하는 것을 추천드립니다:

const crewDataList =
-  (inWhere === 'my-crew'
-    ? data?.pages.flatMap((page) => page?.content as MyCrewList[])
-    : data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? [];
+  (inWhere === 'my-crew'
+    ? data?.pages.flatMap((page) => 
+        Array.isArray(page?.content) && page.content.every(item => 'currentCount' in item)
+          ? page.content
+          : []
+      )
+    : data?.pages?.flatMap((page) =>
+        Array.isArray(page?.content) && page.content.every(item => 'isConfirmed' in item)
+          ? page.content
+          : []
+      )) ?? [];
📝 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
? data?.pages.flatMap((page) => page?.content as MyCrewList[])
: data?.pages?.flatMap((page) => page?.content as MainCrewList[])) ?? [];
(inWhere === 'my-crew'
? data?.pages.flatMap((page) =>
Array.isArray(page?.content) && page.content.every(item => 'currentCount' in item)
? page.content
: []
)
: data?.pages?.flatMap((page) =>
Array.isArray(page?.content) && page.content.every(item => 'isConfirmed' in item)
? page.content
: []
)) ?? [];

const gridColsStyle = inWhere === 'my-crew' ? '' : 'lg:grid-cols-2';

if (data?.pages[0] === undefined)
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/crew-list/crew-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import IcoUser from '@/public/assets/icons/ic-user.svg';
import Profiles from './profiles';

interface CrewCardProps extends MainCrewList {
inWhere?: 'my-crew';
inWhere?: 'my-crew' | 'main-crew';
}

export default function CrewCard({
Expand Down
3 changes: 1 addition & 2 deletions src/types/crew-card.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export interface ConditionTypes {
subCategory: string;
sortType: 'LATEST' | 'POPULAR';
}

export interface PageableTypes {
page: number;
size: number;
Expand Down Expand Up @@ -65,6 +64,6 @@ export interface MyCrewList {
}

export interface MyCrewListResponse {
data: MyCrewList[];
content: MyCrewList[] | undefined;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

content 속성의 undefined 처리 로직이 구현되지 않았습니다.

  • src/components/common/crew-list/crew-card-list.tsx 파일에서 content를 옵셔널 체이닝 없이 사용하고 있습니다.
🔗 Analysis chain

타입 정의가 적절하게 개선되었습니다.

content 속성명으로의 변경과 undefined 타입 추가는 다음과 같은 장점이 있습니다:

  • MainCrewListResponse와의 일관성 확보
  • API 응답 구조와의 정확한 매칭
  • 로딩 상태 및 에러 상태의 명확한 타입 처리 가능

컴포넌트에서 undefined 처리가 적절히 되어있는지 확인이 필요합니다:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: content가 undefined일 때의 처리 로직 확인

# content 속성을 사용하는 컴포넌트 검색
rg -l "\.content\b" --type ts --type tsx

# optional chaining 사용 여부 확인
ast-grep --pattern 'content?' 

Length of output: 102


Script:

#!/bin/bash
# Description: content가 undefined일 때의 처리 로직 확인

# content 속성을 사용하는 컴포넌트 검색
rg -l '\.content\b' -g "*.ts" -g "*.tsx"

# optional chaining 사용 여부 확인
ast-grep --pattern 'content\?.' .

Length of output: 129

hasNext: boolean;
}