Conversation
Walkthrough이 PR은 Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant AEP as AllEventsPage
participant Observer as IntersectionObserver
participant API as Event API
User->>AEP: 스크롤 이벤트 발생
AEP->>Observer: 마지막 이벤트 감시 요청
Observer->>AEP: 감지 후 loadEvents() 호출
AEP->>API: 이벤트 데이터 요청
API-->>AEP: 응답 반환 (이벤트 데이터)
AEP-->>AEP: 상태 업데이트 (events, isLoading, error)
sequenceDiagram
participant MP as MainPage
participant API as Event API
participant State as Component State
MP->>API: useEffect로 이벤트 요청 (latest, trending, closingSoon)
API-->>MP: 응답 반환 (이벤트 목록)
MP->>State: 상태 업데이트 (latestEvents, trendingEvents, closingSoonEvents, isLoading, error)
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (7)
src/pages/home/ui/MainPage.tsx (3)
78-81: 오류 처리 개선 필요현재 오류가 발생하면 간단한 메시지만 표시되고 있습니다. 사용자에게 더 구체적인 정보와 액션(예: 재시도 버튼)을 제공하는 것이 좋습니다.
다음과 같이 재시도 버튼을 추가하는 것을 고려해보세요:
- if (error) { - return <div className="text-center p-4">{error}</div>; - } + if (error) { + return ( + <div className="text-center p-4 flex flex-col items-center"> + <p className="mb-3">{error}</p> + <button + onClick={() => { setError(null); setIsLoading(true); fetchEvents(); }} + className="px-4 py-2 bg-black text-white rounded-lg" + > + 다시 시도하기 + </button> + </div> + ); + }
118-120: 로딩 UI 개선 제안현재 로딩 상태일 때 간단한 텍스트만 표시하고 있습니다. 스켈레톤 UI나 로딩 스피너를 사용하여 사용자 경험을 향상시킬 수 있습니다.
로딩 상태 UI를 개선하기 위한 예시:
- <div className="text-center p-4">이벤트 불러오는 중...ㅎ</div> + <div className="w-full px-6"> + <h2 className="sm:mb-3 md:mb-3.5 lg:mb-4 font-bold sm:text-sm md:text-base lg:text-lg">이벤트 불러오는 중</h2> + <div className="flex gap-4"> + {[1, 2].map((i) => ( + <div key={i} className="w-full h-[300px] bg-gray-200 animate-pulse rounded-lg"></div> + ))} + </div> + </div>
123-158: 중복 로직 개선 제안최신 이벤트, 요즘 뜨는 이벤트, 곧 마감되는 이벤트 섹션이 거의 동일한 구조를 가지고 있습니다. 이를 컴포넌트화하여 코드 중복을 줄일 수 있습니다.
다음과 같이 공통 컴포넌트를 만들어 사용하는 것을 고려해보세요:
// EventSection.tsx 컴포넌트 생성 interface EventSectionProps { title: string; events: EventItem[]; startIndex: number; setStartIndex: Dispatch<SetStateAction<number>>; maxCardsToShow: number; } const EventSection = ({ title, events, startIndex, setStartIndex, maxCardsToShow }: EventSectionProps) => { return ( <div className="relative w-full px-6"> <h2 className="sm:mb-3 md:mb-3.5 lg:mb-4 font-bold sm:text-sm md:text-base lg:text-lg">{title}</h2> <div className="flex gap-4"> {events .slice(startIndex, startIndex + maxCardsToShow) .concat( startIndex + maxCardsToShow > events.length ? events.slice(0, (startIndex + maxCardsToShow) % events.length) : [] ) .map(event => ( <EventCard key={event.id} id={event.id} img={event.bannerImageUrl} eventTitle={event.title} dDay={event.remainDays} host={event.hostChannelName} eventDate={event.startDate} location={event.address} hashtags={event.hashtags} onClick={() => navigate(`/event-details/${event.id}`)} /> ))} </div> {startIndex !== 0 && ( <IconButton iconPath={<img src={leftButton} alt="왼쪽 버튼" className="absolute top-1/2 left-0.5" />} onClick={() => handlePrev(setStartIndex, startIndex, events.length)} /> )} <IconButton iconPath={<img src={rightButton} alt="오른쪽 버튼" className="absolute top-1/2 right-0.5" />} onClick={() => handleNext(setStartIndex, startIndex, events.length)} /> </div> ); }; // MainPage 컴포넌트에서 사용 {/* 최신 이벤트 섹션 */} <EventSection title="최신 이벤트" events={latestEvents} startIndex={latestStartIndex} setStartIndex={setLatestStartIndex} maxCardsToShow={maxCardsToShow} /> {/* 요즘 뜨는 이벤트 섹션 */} <EventSection title="요즘 뜨는 이벤트" events={trendingEvents} startIndex={trendingStartIndex} setStartIndex={setTrendingStartIndex} maxCardsToShow={maxCardsToShow} /> {/* 곧 마감되는 이벤트 섹션 */} <EventSection title="곧 이벤트가 마감돼요! ⏰" events={closingSoonEvents} startIndex={closingStartIndex} setStartIndex={setClosingStartIndex} maxCardsToShow={maxCardsToShow} />Also applies to: 160-195, 197-235
src/shared/api/eventApi.ts (2)
14-19: 에러 처리 개선 필요현재는 API 호출 시 발생할 수 있는 에러가 단순히 호출자에게 전파됩니다. 에러 처리를 보다 구체적으로 구현하는 것이 좋습니다.
try-catch 블록을 사용하여 에러를 표준화하는 방식을 고려해보세요:
getEventByTag: async (tag: EventTag, params: EventParams = { page: 0, size: 10 }): Promise<EventNormalResponse> => { - const response = await axiosClient.get<EventNormalResponse>( - `/events?tags=${tag}&page=${params.page}&size=${params.size}` - ); - return response.data; + try { + const response = await axiosClient.get<EventNormalResponse>( + `/events?tags=${tag}&page=${params.page}&size=${params.size}` + ); + return response.data; + } catch (error) { + console.error(`태그별 이벤트 조회 실패 (${tag}):`, error); + throw { + isSuccess: false, + code: 'API_ERROR', + message: '이벤트를 불러오는데 실패했습니다.', + result: [], + }; + } },
32-38: 검색 기능 개선 제안현재 검색 기능은 키워드만 지원합니다. 필터링 옵션이나 정렬 기능을 추가하면 더 강력한 검색 기능을 제공할 수 있습니다.
다음과 같이 검색 기능을 확장하는 것을 고려해보세요:
interface SearchParams extends EventParams { sortBy?: 'title' | 'startDate' | 'hostChannelName'; order?: 'asc' | 'desc'; category?: EventCategory; } searchEvents: async (keyword: string, params: SearchParams = { page: 0, size: 10 }): Promise<EventNormalResponse> => { const searchParams = new URLSearchParams({ keyword, page: params.page?.toString() || '0', size: params.size?.toString() || '10', }); if (params.sortBy) searchParams.append('sortBy', params.sortBy); if (params.order) searchParams.append('order', params.order); if (params.category) searchParams.append('category', params.category); const response = await axiosClient.get<EventNormalResponse>(`/events/search?${searchParams.toString()}`); return response.data; },src/shared/api/event.txt (2)
1-35: 이벤트 생성 API 명세가 잘 정의되어 있습니다.이벤트 생성을 위한 API 명세가 상세하게 작성되어 있습니다. 요청 헤더와 본문의 필드들이 명확하게 정의되어 있어 좋습니다. 다만, 몇 가지 개선할 점이 있습니다:
- 필수 필드와 선택적 필드를 구분하면 더 명확할 것 같습니다.
- 각 필드의 제약 조건(예: 최대 길이, 허용되는 형식)이 명시되면 좋겠습니다.
182-311: 이벤트 조회 API들의 응답 구조가 일관성 있게 정의되어 있습니다.인기 있는 이벤트, 마감 임박 이벤트, 이벤트 검색 API의 응답 구조가 일관성 있게 정의되어 있어 좋습니다. 각 API의 목적과 호출 방법이 명확하게 설명되어 있습니다.
그러나 마감 임박 이벤트 조회(226-267줄)에서는 "Response Body" 대신 "Request Body"로 잘못 표기되어 있습니다. 이를 수정해야 합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
package.json(2 hunks)src/pages/event/ui/AllEventsPage.tsx(2 hunks)src/pages/home/ui/MainPage.tsx(4 hunks)src/shared/api/event.txt(1 hunks)src/shared/api/eventApi.ts(1 hunks)src/shared/types/api/event.ts(1 hunks)
🧰 Additional context used
🧬 Code Definitions (3)
src/shared/api/eventApi.ts (2)
src/shared/types/api/event.ts (4)
EventNormalResponse(39-39)EventDetailResponse(40-40)EventRequest(43-60)EventResponse(2-7)src/shared/types/api/http-client.ts (1)
axiosClient(6-13)
src/pages/home/ui/MainPage.tsx (2)
src/shared/types/api/event.ts (1)
EventItem(10-20)src/shared/api/eventApi.ts (1)
eventApi(12-63)
src/pages/event/ui/AllEventsPage.tsx (2)
src/shared/types/api/event.ts (2)
EventItem(10-20)EventNormalResponse(39-39)src/shared/api/eventApi.ts (1)
eventApi(12-63)
🔇 Additional comments (22)
package.json (2)
18-18:Details
✅ Verification successful
React Query 버전 업데이트 내역 확인 필요
React Query 라이브러리 버전이
^5.61.3에서^5.72.0으로 업데이트되었습니다. 이는 이벤트 API 연동 작업을 위한 업데이트로 보입니다.최신 버전으로의 업데이트가 필요한 변경사항이 있는지 확인해 주세요:
🌐 Web query:
@tanstack/react-query 5.61.3에서 5.72.0으로 변경된 주요 변경사항이 있나요?💡 Result:
@tanstack/react-query 버전 5.61.3에서 5.72.0으로의 변경사항은 공식 문서와 제공된 검색 결과에 명시적으로 언급되지 않았습니다. 일반적으로 마이너 버전 업데이트는 성능 개선, 버그 수정, 사소한 기능 추가 등을 포함하지만 기존 API를 변경하는 주요 변경사항은 없을 가능성이 높습니다.
주요 변경사항을 확인하려면 공식 GitHub 릴리즈 노트나 문서의 마이그레이션 가이드를 참조해야 합니다. 제공된 검색 결과에서는 v5의 주요 초기 변경사항만 다루고 있으며, 특정 마이너 버전 간 차이점은 포함되지 않았습니다.
검색 결과 [2]에 따르면 TanStack Query v5는 객체 형식 쿼리 정의 강제,
cacheTime→gcTime리네이밍,useErrorBoundary→throwErrors옵션 변경 등 주요 변화를 포함했지만, 이는 v4에서 v5로의 전환 시 변경사항입니다[1][2]. 현재 문의하신 버전 범위(5.61.3 → 5.72.0)는 동일한 메이저 버전 내 업데이트이므로 기존 기능과의 호환성이 유지되었을 것으로 추정됩니다.Citations:
- 1: https://wonsss.github.io/library/tanstack-query-v5/
- 2: https://yeon-code.tistory.com/107
- 3: https://www.npmjs.com/package/@tanstack/react-query
리액트 쿼리 업데이트 로그 검증 완료: 주요 변경사항 없음
React Query의 버전이
^5.61.3에서^5.72.0으로 업데이트되었지만, 공식 문서 및 릴리즈 노트 검색 결과에 따르면 이번 버전 업데이트는 주로 성능 개선, 버그 수정, 사소한 기능 추가 위주로 이루어져 기존 API 변경 사항은 없는 것으로 확인됩니다. 다만, 혹시 모를 세부 변경 사항에 대비하여 공식 릴리즈 노트와 마이그레이션 가이드를 참고해주시길 권장드립니다.
20-20:Details
✅ Verification successful
버전 업데이트 확인
Axios 라이브러리가
^1.8.1에서^1.8.4로 업데이트되었습니다. 새로운 이벤트 API 기능과 관련된 버그 수정이나 보안 패치가 포함되었을 수 있습니다.업데이트된 버전에 중요한 변경사항이 있는지 확인합니다:
🌐 Web query:
axios 1.8.1에서 1.8.4로의 업데이트에 포함된 주요 변경사항은 무엇인가요?💡 Result:
Axios 1.8.1에서 1.8.4로의 업데이트에는 주로 보안 취약점 해결과 종속성 관리 개선이 포함되었습니다. 이 업데이트는 MTC(Migration Toolkit for Containers) 1.8.4 릴리스와 연관되어 있으며, OpenShift 환경에서의 안정성을 강화합니다.
주요 변경사항
보안 취약점 해결
- CVE-2023-45857: Axios의 CSRF(Cross-Site Request Forgery) 취약점이 수정되었습니다. 이전 버전에서는
X-XSRF-TOKEN헤더를 통한 인증 메커니즘에 결함이 있어 공격자가 중요 정보를 탈취할 수 있었으나, 1.8.4에서 해결되었습니다[1][2].- CVE-2024-24786: Golang의
protobuf모듈에서 발생하는 무한 루프 문제가 해결되었습니다. 이전에는 특정 입력 처리 시unmarshal함수가 무한히 실행되어 서비스 거부(DoS) 공격 가능성이 있었습니다[1][2].OpenShift Virtualization 호환성 개선
- MTC 1.8.4에서
python3-openshift패키지의 버그(ValueError: too many values to unpack)로 인한 Ansible Operator 오동작 문제가 해결되었습니다. 이는 Axios의 종속성 관리 개선과 함께 전체 마이그레이션 프로세스의 안정성을 높였습니다[1][2].OADP(OpenShift API for Data Protection) 지원 확대
- OADP 1.4와의 호환성이 추가되어 백업 및 복원 작업 시 데이터 무결성이 개선되었습니다. 이 변경은 Axios의 HTTP 클라이언트 안정성과도 연관되어 있습니다[1].
영향
이 업데이트를 적용하면 KubeVirt 가상 머신 마이그레이션 실패(
no matches for kind VirtualMachine) 및 네임스페이스 충돌 오류와 같은 문제가 해결되며, API 통신 과정에서의 보안성이 강화됩니다[1].Citations:
- 1: https://docs.redhat.com/ko-kr/documentation/openshift_container_platform/4.16/pdf/migration_toolkit_for_containers/OpenShift_Container_Platform-4.16-Migration_Toolkit_for_Containers-ko-KR.pdf
- 2: https://docs.redhat.com/ko-kr/documentation/openshift_container_platform/4.14/pdf/migration_toolkit_for_containers/OpenShift_Container_Platform-4.14-Migration_Toolkit_for_Containers-ko-KR.pdf
- 3: https://any-ting.tistory.com/16
- 4: https://e-7-e.tistory.com/88
버전 업데이트 완료 및 주요 변경사항 반영 확인
- 변경 내용:
axios라이브러리가^1.8.1에서^1.8.4로 업데이트되었습니다.- 업데이트 주요 포인트:
- 보안 취약점 해결
- CVE-2023-45857: CSRF 취약점 수정
- CVE-2024-24786: 무한 루프 문제 해결으로 DoS 공격 가능성 감소
- 종속성 관리 개선 및 OpenShift Virtualization 호환성 강화
- MTC 1.8.4 릴리스와 연계된 개선 사항 적용
- OADP 지원 확대로 백업 및 복원 작업 시 데이터 무결성 강화
해당 업데이트는 보안 강화와 시스템 안정성을 위한 목적에 부합하므로, 별도의 추가 수정 없이 진행해도 무방함을 확인했습니다.
src/pages/home/ui/MainPage.tsx (1)
55-77: API 연동 구현이 잘 되었습니다각 태그별 이벤트(최신, 인기, 마감) 데이터를 비동기적으로 불러오는 로직이 잘 구현되었습니다. Promise.all을 사용하여 여러 API 호출을 효율적으로 처리하고 있습니다.
src/shared/types/api/event.ts (7)
1-7: API 응답 인터페이스 구현 잘 되었습니다Generic을 사용하여 다양한 응답 형태를 처리할 수 있는 유연한 인터페이스를 설계했습니다. 백엔드 API와의 일관성 있는 통신을 위한 좋은 구조입니다.
10-20: 이벤트 기본 정보 인터페이스 구현이 잘 되었습니다이벤트 리스트에 필요한 정보들이 잘 정의되어 있습니다. 현재 UI에 표시되는 정보들과 정확히 매핑되어 있습니다.
23-36: 이벤트 상세 정보 확장 인터페이스
Omit<EventItem, 'remainDays'>를 사용하여 기본 인터페이스를 확장하면서 불필요한 필드를 제거하는 좋은 패턴입니다. 상세 페이지에 필요한 추가 정보들이 잘 정의되어 있습니다.
39-40: 응답 타입 별칭 활용이 적절합니다Generic 인터페이스를 활용하여 응답 타입을 명확하게 정의했습니다. 이렇게 함으로써 코드 가독성과 타입 안정성이 향상됩니다.
43-60: 이벤트 요청 인터페이스 구현이 잘 되었습니다이벤트 생성 및 수정에 필요한 모든 필드가 포함되어 있습니다. 백엔드 API의 요구사항과 일치하는지 확인하세요.
75-78: 온라인 타입 열거형온라인/오프라인 구분을 위한 열거형이 잘 정의되어 있습니다. 추가적인 타입이 필요할 경우(예: 하이브리드) 확장 가능한 구조입니다.
81-86: 카테고리 열거형 확장 가능성 고려현재 4가지 카테고리가 정의되어 있습니다. 향후 새로운 카테고리가 추가될 가능성을 고려해 보세요. 백엔드와 열거형 값이 일치하는지 확인하는 것이 중요합니다.
향후 새로운 카테고리 추가 계획이 있는지, 백엔드와 이 열거형 값이 정확히 일치하는지 확인해주세요.
src/shared/api/eventApi.ts (4)
1-3: 적절한 임포트 구성필요한 의존성과 타입들을 명확하게 임포트하여 코드의 가독성과 유지보수성을 높였습니다. 특히 API 응답과 요청 타입을 재사용하여 일관성을 유지하고 있습니다.
4-5: 태그와 카테고리 타입 정의문자열 리터럴 타입을 사용하여 가능한 태그와 카테고리 값을 명확하게 정의했습니다. 이는 컴파일 시점에 오류를 잡아내는 데 도움이 됩니다.
7-10: 페이지네이션 파라미터 인터페이스페이지네이션 관련 파라미터를 별도의 인터페이스로 분리한 것은 좋은 접근입니다. 선택적(optional) 속성으로 정의하여 유연성을 확보했습니다.
12-63: API 메서드 구현의 일관성이 좋습니다모든 API 메서드가 일관된 패턴으로 구현되어 있습니다. 각 메서드는 명확한 주석, 적절한 매개변수, 그리고 타입 안전성을 갖추고 있습니다. 에러 처리는 호출자에게 위임되어 있어 유연성을 제공합니다.
src/pages/event/ui/AllEventsPage.tsx (6)
9-11: 적절한 import 업데이트.하드코딩된 트렌딩 이벤트 import를 제거하고 API 관련 import를 추가한 것은 좋은 변경입니다. 이제 실제 API에서 이벤트 데이터를 가져올 수 있게 되었습니다.
15-22: 상태 관리 구현이 잘 되어 있습니다.이벤트 데이터, 로딩 상태, 에러 처리, 페이지네이션 및 무한 스크롤을 위한 상태 변수들이 적절하게 정의되어 있습니다. 특히
IntersectionObserver를 위한 ref와 로딩 표시를 위한 ref를 분리한 것이 좋습니다.
65-81: IntersectionObserver를 활용한 무한 스크롤 구현이 잘 되어 있습니다.
lastEventRef콜백 함수가 효율적으로 구현되어 있습니다. 특히:
- 불필요한 observer 생성을 방지하기 위한 조건 검사
- 이전 observer의 연결 해제
- 의존성 배열이 올바르게 설정됨
이는 성능과 메모리 관리 측면에서 좋은 구현입니다.
83-90: useEffect 내 메모리 누수 방지 코드 좋습니다.컴포넌트 마운트 시 초기 이벤트를 로드하고, 언마운트 시 observer를 정리하는 로직이 잘 구현되어 있습니다. 이는 메모리 누수를 방지하는 좋은 방법입니다.
109-122: 이벤트 리스트 렌더링 로직이 잘 구현되어 있습니다.이벤트 카드 렌더링 로직이 적절하게 구현되어 있으며,
lastEventRef를 마지막 아이템에만 연결하는 조건부 로직이 효율적입니다. 또한 EventCard 컴포넌트에 필요한 모든 속성이 올바르게 전달되고 있습니다.
125-136: 사용자 피드백 UI가 잘 구현되어 있습니다.로딩 상태, 에러 메시지, 더 이상 표시할 이벤트가 없을 때의 메시지 등 다양한 상태에 대한 사용자 피드백이 잘 구현되어 있습니다. 이는 사용자 경험을 향상시키는 좋은 방법입니다.
src/shared/api/event.txt (2)
37-82: 이벤트 상세 조회 API 명세가 잘 정의되어 있습니다.이벤트 상세 정보를 조회하기 위한 API 구조가 명확합니다. 응답 본문이 상세하게 작성되어 있어 프론트엔드 개발자가 쉽게 이해할 수 있습니다.
한 가지 주의할 점은 예제에서
endDate가startDate보다 이전인 것으로 보입니다(55-56줄). 실제 API에서는 날짜 유효성 검사가 필요할 것 같습니다.
121-135: 이벤트 삭제 API 명세가 간결하고 명확합니다.이벤트 삭제 API 명세가 잘 작성되어 있습니다. 삭제 요청의 구조와 성공 응답이 명확하게 정의되어 있습니다.
| export enum EventStatus { | ||
| PROGRESS = 'PROGRESS', | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
이벤트 상태 열거형 확장 필요
현재는 'PROGRESS' 상태만 정의되어 있습니다. 일반적으로 이벤트는 더 다양한 상태(예: 예정됨, 취소됨, 완료됨 등)를 가질 수 있습니다.
더 다양한 상태를 추가하는 것이 좋습니다:
export enum EventStatus {
PROGRESS = 'PROGRESS',
+ SCHEDULED = 'SCHEDULED',
+ CANCELED = 'CANCELED',
+ COMPLETED = 'COMPLETED',
}📝 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.
| export enum EventStatus { | |
| PROGRESS = 'PROGRESS', | |
| } | |
| export enum EventStatus { | |
| PROGRESS = 'PROGRESS', | |
| SCHEDULED = 'SCHEDULED', | |
| CANCELED = 'CANCELED', | |
| COMPLETED = 'COMPLETED', | |
| } |
| const response = await axiosClient.get<EventNormalResponse>( | ||
| `/events?tags=${tag}&page=${params.page}&size=${params.size}` | ||
| ); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
URL 파라미터 처리 개선
URL 파라미터를 문자열 보간법으로 직접 구성하고 있습니다. 이는 특수 문자가 포함된 경우 문제가 될 수 있습니다.
URLSearchParams를 사용하여 안전하게 URL 매개변수를 처리하는 것이 좋습니다:
- const response = await axiosClient.get<EventNormalResponse>(
- `/events?tags=${tag}&page=${params.page}&size=${params.size}`
- );
+ const searchParams = new URLSearchParams({
+ tags: tag,
+ page: params.page?.toString() || '0',
+ size: params.size?.toString() || '10',
+ });
+ const response = await axiosClient.get<EventNormalResponse>(`/events?${searchParams.toString()}`);📝 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.
| const response = await axiosClient.get<EventNormalResponse>( | |
| `/events?tags=${tag}&page=${params.page}&size=${params.size}` | |
| ); | |
| const searchParams = new URLSearchParams({ | |
| tags: tag, | |
| page: params.page?.toString() || '0', | |
| size: params.size?.toString() || '10', | |
| }); | |
| const response = await axiosClient.get<EventNormalResponse>(`/events?${searchParams.toString()}`); |
| const loadEvents = async (pageNum: number) => { | ||
| try { | ||
| setIsLoading(true); | ||
| console.log('Fetching events with params:', { page: pageNum, size: 10 }); | ||
| const response: EventNormalResponse = await eventApi.getEventByTag('current', { page: pageNum, size: 10 }); | ||
| console.log('API Response:', response); | ||
|
|
||
| if (response?.result && Array.isArray(response.result)) { | ||
| console.log('Total events received:', response.result.length); | ||
|
|
||
| if (response.result.length === 0) { | ||
| console.log('No more events to load'); | ||
| setHasMore(false); | ||
| } else { | ||
| if (pageNum === 0) { | ||
| console.log('Setting initial events'); | ||
| setEvents(response.result); | ||
| } else { | ||
| console.log('Adding more events'); | ||
| setEvents(prev => { | ||
| // 중복 제거 | ||
| const newEvents = response.result.filter( | ||
| newEvent => !prev.some(existingEvent => existingEvent.id === newEvent.id) | ||
| ); | ||
| console.log('New events to add:', newEvents.length); | ||
| return [...prev, ...newEvents]; | ||
| }); | ||
| } | ||
| setPage(pageNum); | ||
| } | ||
| } else { | ||
| console.error('Invalid response format:', response); | ||
| setError('이벤트 데이터 형식이 올바르지 않습니다.'); | ||
| } | ||
| } catch (err) { | ||
| console.error('Error details:', err); | ||
| setError('이벤트를 불러오는데 실패했습니다.'); | ||
| } finally { | ||
| setIsLoading(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
loadEvents 함수에 몇 가지 개선 사항이 필요합니다.
이벤트를 불러오는 함수가 잘 구현되어 있지만, 몇 가지 개선할 점이 있습니다:
- 불필요한 console.log 문이 많이 포함되어 있습니다. 프로덕션 코드에서는 제거하는 것이 좋습니다.
- 에러 처리 시 더 구체적인 에러 메시지를 표시하면 디버깅에 도움이 될 것입니다.
const loadEvents = async (pageNum: number) => {
try {
setIsLoading(true);
- console.log('Fetching events with params:', { page: pageNum, size: 10 });
const response: EventNormalResponse = await eventApi.getEventByTag('current', { page: pageNum, size: 10 });
- console.log('API Response:', response);
if (response?.result && Array.isArray(response.result)) {
- console.log('Total events received:', response.result.length);
if (response.result.length === 0) {
- console.log('No more events to load');
setHasMore(false);
} else {
if (pageNum === 0) {
- console.log('Setting initial events');
setEvents(response.result);
} else {
- console.log('Adding more events');
setEvents(prev => {
// 중복 제거
const newEvents = response.result.filter(
newEvent => !prev.some(existingEvent => existingEvent.id === newEvent.id)
);
- console.log('New events to add:', newEvents.length);
return [...prev, ...newEvents];
});
}
setPage(pageNum);
}
} else {
- console.error('Invalid response format:', response);
+ console.error('Invalid response format:', response);
setError('이벤트 데이터 형식이 올바르지 않습니다.');
}
} catch (err) {
- console.error('Error details:', err);
+ console.error('Error fetching events:', err);
+ const errorMessage = err instanceof Error ? `이벤트를 불러오는데 실패했습니다: ${err.message}` : '이벤트를 불러오는데 실패했습니다.';
- setError('이벤트를 불러오는데 실패했습니다.');
+ setError(errorMessage);
} finally {
setIsLoading(false);
}
};📝 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.
| const loadEvents = async (pageNum: number) => { | |
| try { | |
| setIsLoading(true); | |
| console.log('Fetching events with params:', { page: pageNum, size: 10 }); | |
| const response: EventNormalResponse = await eventApi.getEventByTag('current', { page: pageNum, size: 10 }); | |
| console.log('API Response:', response); | |
| if (response?.result && Array.isArray(response.result)) { | |
| console.log('Total events received:', response.result.length); | |
| if (response.result.length === 0) { | |
| console.log('No more events to load'); | |
| setHasMore(false); | |
| } else { | |
| if (pageNum === 0) { | |
| console.log('Setting initial events'); | |
| setEvents(response.result); | |
| } else { | |
| console.log('Adding more events'); | |
| setEvents(prev => { | |
| // 중복 제거 | |
| const newEvents = response.result.filter( | |
| newEvent => !prev.some(existingEvent => existingEvent.id === newEvent.id) | |
| ); | |
| console.log('New events to add:', newEvents.length); | |
| return [...prev, ...newEvents]; | |
| }); | |
| } | |
| setPage(pageNum); | |
| } | |
| } else { | |
| console.error('Invalid response format:', response); | |
| setError('이벤트 데이터 형식이 올바르지 않습니다.'); | |
| } | |
| } catch (err) { | |
| console.error('Error details:', err); | |
| setError('이벤트를 불러오는데 실패했습니다.'); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; | |
| const loadEvents = async (pageNum: number) => { | |
| try { | |
| setIsLoading(true); | |
| const response: EventNormalResponse = await eventApi.getEventByTag('current', { page: pageNum, size: 10 }); | |
| if (response?.result && Array.isArray(response.result)) { | |
| if (response.result.length === 0) { | |
| setHasMore(false); | |
| } else { | |
| if (pageNum === 0) { | |
| setEvents(response.result); | |
| } else { | |
| setEvents(prev => { | |
| // 중복 제거 | |
| const newEvents = response.result.filter( | |
| newEvent => !prev.some(existingEvent => existingEvent.id === newEvent.id) | |
| ); | |
| return [...prev, ...newEvents]; | |
| }); | |
| } | |
| setPage(pageNum); | |
| } | |
| } else { | |
| console.error('Invalid response format:', response); | |
| setError('이벤트 데이터 형식이 올바르지 않습니다.'); | |
| } | |
| } catch (err) { | |
| console.error('Error fetching events:', err); | |
| const errorMessage = err instanceof Error ? `이벤트를 불러오는데 실패했습니다: ${err.message}` : '이벤트를 불러오는데 실패했습니다.'; | |
| setError(errorMessage); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; |
| < 이벤트 수정 > | ||
|
|
||
| - Path Variable | ||
| "eventId" : 1 | ||
|
|
||
| - Request Headers | ||
| "Authorization" : "ACCESS_TOKEN", | ||
|
|
||
| - Request Body{ | ||
| "title": "string", | ||
| "startDate": "2024-12-25", | ||
| "endDate": "2024-12-31", | ||
| "startTime": "15:30", | ||
| "endTime": "20:00", | ||
| "bannerImageUrl": "string", | ||
| "description": "string", | ||
| "referenceLinks": { | ||
| "additionalProp1": "string", | ||
| "additionalProp2": "string", | ||
| "additionalProp3": "string" | ||
| }, | ||
| "onlineType": "ONLINE", [ ONLINE, OFFLINE ] | ||
| "address": "string", | ||
| "location": { | ||
| "lat": 123.00, | ||
| "lng": 123.00 | ||
| }, | ||
| "category": "DEVELOPMENT_STUDY", [ DEVELOPMENT_STUDY, NETWORKING, HACKATHON, CONFERENCE] | ||
| "hashtags": [ | ||
| "string", "string2" | ||
| ], | ||
| "hostEmail": "string", | ||
| "hostPhoneNumber": "string" | ||
| } |
There was a problem hiding this comment.
이벤트 수정 API의 referenceLinks 구조가 생성 API와 다릅니다.
이벤트 수정 API의 referenceLinks 필드 구조가 이벤트 생성 API와 다르게 정의되어 있습니다:
- 생성 API:
referenceLinks는title과url필드를 가진 객체의 배열 - 수정 API:
referenceLinks는additionalProp1,additionalProp2,additionalProp3키를 가진 객체
두 API 간에 일관성이 필요합니다. 또한 이벤트 수정 API에서 hostEmail과 hostPhoneNumber 필드가 있는데, 생성 API에서는 organizerEmail과 organizerPhoneNumber로 명명되어 있습니다. 이름을 일관되게 통일해야 합니다.
There was a problem hiding this comment.
아 이거는 API 연동하면서 옮겨적은거라 나중에 지우도록 할게요!
There was a problem hiding this comment.
@xaexunxang 알겠습니다! 참고용 문서라면 나중에 삭제하셔도 괜찮을 것 같습니다. API 연동 작업 잘 진행되고 있는 것 같아 보입니다. 👍
ʕ •ᴥ•ʔ
| < 최신 이벤트 조회 > | ||
|
|
||
| - Query Variable | ||
| "tags" : "current" | ||
|
|
||
| - Request Headers | ||
| "Authorization" : "ACCESS_TOKEN", | ||
|
|
||
| - Response Body | ||
| { | ||
| "isSuccess": true, | ||
| "code": "200", | ||
| "message": "OK", | ||
| "result": [ | ||
| { | ||
| "id": 21, | ||
| "bannerImageUrl": "string", | ||
| "title": "string", | ||
| "hostChannelName": "테커", | ||
| "startDate": "2025-04-02", | ||
| "address": "string", | ||
| "onlineType": "ONLINE", | ||
| "hashtags": [ | ||
| "string" | ||
| ], | ||
| "remainDays": "D-1" | ||
| }, | ||
| { | ||
| "id": 20, | ||
| "bannerImageUrl": "string", | ||
| "title": "string", | ||
| "hostChannelName": "테커", | ||
| "startDate": "2025-04-02", | ||
| "address": "string", | ||
| "onlineType": "ONLINE", | ||
| "hashtags": [ | ||
| "string" | ||
| ], | ||
| "remainDays": "D-1" | ||
| } | ||
| ] | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
최신 이벤트 조회 API 명세가 잘 정의되어 있습니다.
최신 이벤트를 조회하기 위한 API가 명확하게 정의되어 있습니다. 쿼리 변수와 응답 본문의 구조가 상세하게 작성되어 있어 좋습니다.
다만, 페이지네이션 관련 파라미터(page, size)가 명시되어 있지 않습니다. AllEventsPage 컴포넌트에서는 이러한 파라미터를 사용하고 있으므로, API 명세에도 포함되어야 합니다.
메인 페이지 이벤트 조회 API 연동
전체 이벤트 무한 스크롤 구현
Summary by CodeRabbit