Conversation
Walkthrough이 변경사항은 이벤트 목록의 무한 스크롤, 태그 기반 이벤트 조회, 슬라이더 섹션 등 이벤트 관련 UI 및 API 기능을 대폭 확장합니다. 이벤트 목록, 슬라이더, 태그별 섹션 등 새로운 컴포넌트와 관련 커스텀 훅, 타입이 추가되었으며, 기존의 불필요한 import 및 로직이 정리되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant EventList
participant useInfiniteScroll
participant API
User->>EventList: 페이지 진입/스크롤
EventList->>useInfiniteScroll: 다음 이벤트 페이지 요청
useInfiniteScroll->>API: getAllEventsInfinite({page, size, tag})
API-->>useInfiniteScroll: { items, hasNextPage }
useInfiniteScroll-->>EventList: 데이터 및 hasNextPage 전달
EventList-->>User: 이벤트 카드 목록 렌더링, 추가 데이터 자동 로드
sequenceDiagram
participant User
participant EventTags
participant useLatestEvents
participant useTrendingEvents
participant useClosingSoonEvents
participant API
User->>EventTags: 메인 페이지 진입
EventTags->>useLatestEvents: 최신 이벤트 요청
EventTags->>useTrendingEvents: 트렌딩 이벤트 요청
EventTags->>useClosingSoonEvents: 마감임박 이벤트 요청
useLatestEvents->>API: getEventByTag('current')
useTrendingEvents->>API: getEventByTag('popular')
useClosingSoonEvents->>API: getEventByTag('deadline')
API-->>useLatestEvents: 최신 이벤트 데이터
API-->>useTrendingEvents: 트렌딩 이벤트 데이터
API-->>useClosingSoonEvents: 마감임박 이벤트 데이터
EventTags-->>User: 각 카테고리별 슬라이더 렌더링
Possibly related PRs
Suggested labels
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (17)
💤 Files with no reviewable changes (1)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (15)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ 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:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
src/entities/event/api/event.ts (1)
1-72: 🛠️ Refactor suggestion에러 처리 로직이 없습니다.
API 호출 중 발생할 수 있는 예외 상황에 대한 처리가 없습니다. try/catch 구문을 사용하여 에러를 적절히 처리하는 것이 좋습니다.
모든 API 함수에 에러 처리 로직을 추가하세요. 예시:
export const getEventById = async (eventId: number): Promise<EventDetailResponse> => { + try { const response = await axiosClient.get<EventDetailResponse>(`/events/${eventId}`); return response.data; + } catch (error) { + console.error('이벤트 상세 정보를 불러오는 중 오류가 발생했습니다:', error); + throw error; + } };🧰 Tools
🪛 Biome (1.9.4)
[error] 63-64: Unexpected label.
Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.(lint/suspicious/noConfusingLabels)
🪛 ESLint
[error] 62-62: 'updateEvent:' is defined but never used.
(no-unused-labels)
[error] 62-65: Expected an assignment or function call and instead saw an expression.
(@typescript-eslint/no-unused-expressions)
🧹 Nitpick comments (9)
src/entities/event/model/eventMeta.ts (1)
1-45: 이벤트 메타데이터 타입 정의가 잘 구성되어 있습니다.전체적으로 이벤트 관련 타입 및 인터페이스 정의가 잘 구조화되어 있습니다. 한국어 주석도 이해하기 쉽게 작성되어 있어 좋습니다.
다만 몇 가지 개선 사항을 제안드립니다:
EventCategory 타입(3번 라인)과 Category 열거형(35-40번 라인)이 동일한 값을 중복 정의하고 있습니다. 일관성을 위해 하나만 사용하거나 명확한 목적을 가진 타입으로 분리하는 것이 좋겠습니다.
EventStatus 열거형이 현재 'PROGRESS'만 정의되어 있는데, 이벤트의 다른 상태(예: 'COMPLETED', 'CANCELED', 'UPCOMING' 등)도 추후 필요할 수 있으니 고려해보세요.
export enum EventStatus { PROGRESS = 'PROGRESS', + COMPLETED = 'COMPLETED', + CANCELED = 'CANCELED', + UPCOMING = 'UPCOMING', }src/entities/event/model/eventRequest.ts (1)
1-17: EventRequest 인터페이스 구조가 잘 정의되어 있습니다.이벤트 요청을 위한 기본 인터페이스가 잘 정의되어 있습니다. 필요한 필드들이 포함되어 있고 관련 타입들을 적절히 import하여 사용하고 있습니다.
다만 몇 가지 고려할 점이 있습니다:
- 현재 모든 필드가 필수로 되어 있습니다. 특정 상황에서 선택적으로 필요한 필드가 있다면
?를 사용하여 선택적 필드로 표시하는 것이 좋습니다.- 날짜 관련 필드(startDate, endDate, startTime, endTime)의 형식에 대한 설명 주석이 있으면 더 명확할 것 같습니다. (예: "YYYY-MM-DD" 형식)
export interface EventRequest { title: string; + // YYYY-MM-DD 형식 startDate: string; + // YYYY-MM-DD 형식 endDate: string; + // HH:MM 형식 startTime: string; + // HH:MM 형식 endTime: string; bannerImageUrl: string; description: string; referenceLinks: ReferenceLink[]; onlineType: OnlineType; - address: string; + address: string; // 오프라인 이벤트인 경우 필수 - location: Location; + location: Location; // 오프라인 이벤트인 경우 필수 category: Category; hashtags: string[]; }src/features/event-manage/event-list/ui/EventList.tsx (2)
31-56: 로딩 및 오류 상태 처리 개선 필요현재 구현에서는 로딩 상태 표시가 목록 하단에만 있으며, 초기 로딩 상태와 오류 상태에 대한 처리가 없습니다. 사용자 경험을 향상시키기 위해 이러한 상태를 처리하는 것이 좋습니다.
return ( <> + {data?.pages[0]?.items.length === 0 && ( + <div className="text-center py-4">이벤트가 없습니다.</div> + )} + {!data && isFetching && ( + <div className="text-center py-4">이벤트를 불러오는 중...</div> + )} <div className="grid grid-cols-2 gap-4 mx-6 mt-2 md:grid-cols-2 lg:grid-cols-2"> {data?.pages.map((page, pageIndex) => page.items.map((event: EventItem, eventIndex) => { const isLastElement = pageIndex === data.pages.length - 1 && eventIndex === page.items.length - 1; return ( <div key={event.id} ref={isLastElement ? lastEventCardRef : null}> <EventCard id={event.id} img={event.bannerImageUrl} eventTitle={event.title} eventDate={event.startDate} location={event.address} host={event.hostChannelName} hashtags={event.hashtags} dDay={event.remainDays} /> </div> ); }) )} </div> {isFetching && <div className="text-center py-4">Loading...</div>} </> );
33-33: 반응형 그리드 레이아웃 개선현재 그리드 레이아웃은 모든 화면 크기에서
grid-cols-2로 설정되어 있어 실질적으로 반응형이 적용되지 않습니다. 화면 크기에 따라 표시되는 열 수를 조정하여 더 나은 사용자 경험을 제공하는 것이 좋습니다.- <div className="grid grid-cols-2 gap-4 mx-6 mt-2 md:grid-cols-2 lg:grid-cols-2"> + <div className="grid grid-cols-1 gap-4 mx-6 mt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">src/features/event-manage/event-list/hooks/useInfiniteScroll.ts (1)
14-21: 훅 구현이 훌륭합니다제네릭 타입을 사용하여 재사용 가능한 무한 스크롤 훅을 구현한 것이 좋습니다. 하지만, 오류 처리와 재시도 로직이 없습니다. 네트워크 오류나 API 응답 실패 시 대응 방법을 추가하는 것이 좋겠습니다.
export const useInfiniteScroll = <T>({ queryKey, queryFn, size = 10, filters }: UseInfiniteScrollProps<T>) => { return useInfiniteQuery({ queryKey, queryFn: ({ pageParam = 0 }) => queryFn({ page: pageParam, size, ...filters }), getNextPageParam: (lastPage, allPages) => (lastPage.hasNextPage ? allPages.length : undefined), initialPageParam: 0, + retry: 2, + retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), + onError: (error) => { + console.error('무한 스크롤 데이터 로딩 중 오류 발생:', error); + } }); };src/entities/event/model/eventResponse.ts (1)
10-11: 코드 주석이 한글로 작성되어 있습니다코드 주석이 한글로 작성되어 있는데, 코드베이스의 일관성을 위해 주석 언어를 통일하는 것이 좋습니다. 팀의 코딩 컨벤션에 따라 모든 주석을 영어로 작성하거나, 한글을 표준으로 사용한다면 모든 파일에서 일관되게 적용해야 합니다.
- export type EventNormalResponse = EventResponse<EventItem[]>; // 이벤트 최신, 인기, 마감, 검색 - export type EventDetailResponse = EventResponse<EventDetail>; // 이벤트 상세 + export type EventNormalResponse = EventResponse<EventItem[]>; // Event listing: latest, popular, deadline, search + export type EventDetailResponse = EventResponse<EventDetail>; // Event detailsrc/features/home/ui/EventTags.tsx (1)
46-163: 중복 코드가 많이 존재합니다.세 개의 이벤트 섹션이 거의 동일한 구조를 가지고 있어 코드 중복이 많습니다. 컴포넌트를 분리하여 재사용성을 높이는 것이 좋겠습니다.
별도의 컴포넌트로 분리하는 것을 권장합니다:
type EventSectionProps = { title: string; events: { result: EventItem[] }; startIndex: number; setStartIndex: Dispatch<SetStateAction<number>>; }; const EventSection = ({ title, events, startIndex, setStartIndex }: EventSectionProps) => { const maxCardsToShow = 2; const navigate = useNavigate(); 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> {events.result.length === 0 ? ( <p className="text-gray-500">표시할 이벤트가 없습니다.</p> ) : ( <div className="flex gap-4"> {events.result .slice(startIndex, startIndex + maxCardsToShow) .concat( startIndex + maxCardsToShow > events.result.length ? events.result.slice(0, (startIndex + maxCardsToShow) % events.result.length) : [] ) .map((event: EventItem) => ( <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 && events.result.length > 0 && ( <IconButton iconPath={<img src={leftButton} alt="왼쪽 버튼" className="absolute top-1/2 left-0.5" />} onClick={() => handlePrev(setStartIndex, startIndex, events.result.length)} /> )} {events.result.length > 0 && ( <IconButton iconPath={<img src={rightButton} alt="오른쪽 버튼" className="absolute top-1/2 right-0.5" />} onClick={() => handleNext(setStartIndex, startIndex, events.result.length)} /> )} </div> ); }; // 사용 예시: <> <EventSection title="최신 이벤트" events={latestEvents} startIndex={latestStartIndex} setStartIndex={setLatestStartIndex} /> <EventSection title="요즘 뜨는 이벤트" events={trendingEvents} startIndex={trendingStartIndex} setStartIndex={setTrendingStartIndex} /> <EventSection title="곧 이벤트가 마감돼요! ⏰" events={closingSoonEvents} startIndex={closingStartIndex} setStartIndex={setClosingStartIndex} /> </>src/entities/event/api/event.ts (2)
22-24: URL 구성을 개선할 수 있습니다.현재 URL 구성 방식은 가독성이 떨어지고 오류가 발생하기 쉽습니다. URLSearchParams를 사용하여 더 안전하게 URL을 구성하는 것이 좋습니다.
- const response = await axiosClient.get<EventNormalResponse>( - `/events${tag ? `?tags=${tag}` : ''}${tag ? '&' : '?'}page=${page}&size=${size}` - ); + const params = new URLSearchParams(); + if (tag) params.append('tags', tag); + params.append('page', page.toString()); + params.append('size', size.toString()); + const response = await axiosClient.get<EventNormalResponse>(`/events?${params.toString()}`);
16-30: 반환 타입 일관성 개선 필요다른 함수들은 API 응답 타입을 직접 반환하는데,
getAllEventsInfinite함수만 다른 형태로 반환합니다. 일관성을 위해 유사한 방식으로 구현하는 것이 좋습니다.동일한 응답 타입을 사용하거나, 별도의 인터페이스를 만들어 명시적으로 정의하는 것이 좋습니다.
// model/eventResponse.ts에 추가 export interface EventInfiniteResponse { items: EventItem[]; hasNextPage: boolean; } // 함수 선언부 변경 export const getAllEventsInfinite = async ({ page, size, tag, }: PaginationParams & { tag?: EventTag }): Promise<EventInfiniteResponse> => { // 함수 내용은 동일 };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
src/app/routes/Router.tsx(0 hunks)src/entities/event/api/event.ts(1 hunks)src/entities/event/model/event.ts(1 hunks)src/entities/event/model/eventMeta.ts(1 hunks)src/entities/event/model/eventRequest.ts(1 hunks)src/entities/event/model/eventResponse.ts(1 hunks)src/features/event-manage/event-list/hooks/useInfiniteScroll.ts(1 hunks)src/features/event-manage/event-list/ui/EventList.tsx(1 hunks)src/features/home/ui/EventTags.tsx(1 hunks)src/pages/event/ui/AllEventsPage.tsx(2 hunks)src/pages/home/ui/MainPage.tsx(3 hunks)src/shared/types/api/http-client.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/app/routes/Router.tsx
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/entities/event/model/eventResponse.ts (1)
src/entities/event/model/event.ts (2)
EventItem(4-14)EventDetail(17-30)
src/entities/event/model/eventRequest.ts (1)
src/entities/event/model/eventMeta.ts (2)
ReferenceLink(17-20)Location(23-26)
src/features/event-manage/event-list/ui/EventList.tsx (3)
src/features/event-manage/event-list/hooks/useInfiniteScroll.ts (1)
useInfiniteScroll(14-21)src/entities/event/model/event.ts (1)
EventItem(4-14)src/entities/event/api/event.ts (1)
getAllEventsInfinite(17-30)
src/entities/event/model/event.ts (1)
src/entities/event/model/eventMeta.ts (2)
Location(23-26)ReferenceLink(17-20)
src/features/event-manage/event-list/hooks/useInfiniteScroll.ts (1)
src/entities/event/model/eventMeta.ts (2)
PaginationParams(11-14)EventFilters(5-9)
🪛 Biome (1.9.4)
src/entities/event/api/event.ts
[error] 63-64: Unexpected label.
Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.
(lint/suspicious/noConfusingLabels)
🪛 ESLint
src/entities/event/api/event.ts
[error] 62-62: 'updateEvent:' is defined but never used.
(no-unused-labels)
[error] 62-65: Expected an assignment or function call and instead saw an expression.
(@typescript-eslint/no-unused-expressions)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: storybook
🔇 Additional comments (10)
src/shared/types/api/http-client.ts (1)
48-48: 공백 제거 변경이 적절합니다.코드 포맷팅을 위한 공백 제거 변경으로 적절합니다.
src/pages/event/ui/AllEventsPage.tsx (1)
6-6: EventList 컴포넌트 도입으로 코드가 간결해졌습니다.이전에 개별 EventCard 컴포넌트들을 반복 렌더링하던 방식에서 재사용 가능한 EventList 컴포넌트로 대체함으로써 코드가 훨씬 간결해졌습니다. 이제 이벤트 데이터 페칭과 렌더링 로직이 모두 EventList 컴포넌트에 캡슐화되어 유지보수가 더 용이해졌습니다.
다만 EventList 컴포넌트에 어떤 속성(props)도 전달하지 않고 있는데, 필터링 옵션이나 페이지네이션 설정 등이 필요하지는 않은지 확인해보세요.
Also applies to: 29-29
src/entities/event/model/eventRequest.ts (1)
19-24: EventCreate 인터페이스가 잘 확장되었습니다.EventRequest를 확장한 EventCreate 인터페이스가 명확하게 정의되어 있으며, 주석을 통해 용도(POST, 이벤트 생성)가 잘 설명되어 있습니다.
src/pages/home/ui/MainPage.tsx (3)
68-69: 이벤트 태그 섹션 구현 좋습니다!이전의 수동 이벤트 목록 렌더링 대신 재사용 가능한
EventTag컴포넌트를 사용하여 코드가 더 깔끔하고 유지보수가 용이해졌습니다. 태그별 이벤트 분류는 사용자 경험 측면에서도 좋은 접근입니다.
25-25: 인증 상태 관리 개선useAuthStore에서 추출한 값들이 잘 사용되고 있습니다. 코드가 더 명확해졌습니다.
41-48: SecondaryButton 구성 개선버튼 속성을 더 명확하게 구성하셨습니다. 조건부 레이블과 클릭 핸들러 로직이 잘 구현되어 있습니다.
src/features/event-manage/event-list/hooks/useInfiniteScroll.ts (1)
4-12: 인터페이스 정의가 잘 되어 있습니다
UseInfiniteScrollProps인터페이스가 명확하게 정의되어 있으며, 필요한 파라미터들이 잘 포함되어 있습니다. 제네릭 타입T를 사용하여 다양한 데이터 타입에 대응할 수 있게 한 것도 좋은 설계입니다.src/entities/event/model/eventResponse.ts (1)
3-8: 응답 인터페이스 설계가 좋습니다제네릭 타입을 사용한
EventResponse<T>인터페이스가 API 응답 구조를 명확하게 정의하고 있습니다. 이를 통해 다양한 이벤트 관련 응답을 타입 안전하게 처리할 수 있습니다.src/entities/event/model/event.ts (1)
1-30: 코드 구조가 명확하고 타입 정의가 잘 되어 있습니다.인터페이스 설계가 깔끔하게 되어 있으며,
EventItem과EventDetail의 관계가Omit을 통해 적절하게 구현되었습니다. 주석을 통한 설명도 명확합니다.src/features/home/ui/EventTags.tsx (1)
36-42: 잘 구현된 nagivation 핸들러 함수입니다.
handleNext와handlePrev함수를 통해 재사용 가능한 방식으로 네비게이션 로직을 구현한 점이 좋습니다.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/pages/home/ui/MainPage.tsx (1)
35-35: 여전히 불필요한 빈 onChange 핸들러가 있습니다.이전 리뷰에서 지적된 내용이 아직 수정되지 않았습니다. 빈 onChange 핸들러는 불필요합니다.
🧹 Nitpick comments (2)
src/features/home/ui/EventSliderSection.tsx (2)
55-64: 네비게이션 버튼 UI 개선을 고려해 보세요.왼쪽 버튼이
startIndex !== 0일 때만 표시되는데, 이렇게 하면 사용자가 처음 위치에서 뒤로 이동할 수 있다는 것을 인지하지 못할 수 있습니다.일관성을 위해 오른쪽 버튼처럼 왼쪽 버튼도 항상 표시하는 것이 좋습니다:
- {startIndex !== 0 && ( <IconButton iconPath={<img src={leftButton} alt="왼쪽 버튼" className="absolute top-1/2 left-0.5" />} onClick={() => handlePrev(setStartIndex, startIndex, events.length)} /> - )}또한 접근성을 높이기 위해 아이콘 버튼에 aria-label을 추가하는 것이 좋습니다:
<IconButton iconPath={<img src={leftButton} alt="왼쪽 버튼" className="absolute top-1/2 left-0.5" />} onClick={() => handlePrev(setStartIndex, startIndex, events.length)} + aria-label="이전 이벤트 보기" />
29-67: 성능 최적화를 고려해 보세요.현재 코드는 매 렌더링마다 배열 조작을 수행합니다. 이는 useMemo를 사용하여 최적화할 수 있습니다.
+ import { useState, Dispatch, SetStateAction, useMemo } from 'react'; // 컴포넌트 내부 + const displayEvents = useMemo(() => { + return events + .slice(startIndex, startIndex + maxCardsToShow) + .concat( + startIndex + maxCardsToShow > events.length + ? events.slice(0, (startIndex + maxCardsToShow) % events.length) + : [] + ); + }, [events, startIndex, maxCardsToShow]); // JSX 내부 <div className="flex gap-4"> - {events - .slice(startIndex, startIndex + maxCardsToShow) - .concat( - startIndex + maxCardsToShow > events.length - ? events.slice(0, (startIndex + maxCardsToShow) % events.length) - : [] - ) + {displayEvents .map((event: EventItem) => ( // ... ))} </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/entities/event/api/event.ts(1 hunks)src/entities/event/model/eventRequest.ts(1 hunks)src/features/event-manage/event-list/ui/EventList.tsx(1 hunks)src/features/home/hooks/useEventHook.ts(1 hunks)src/features/home/model/eventResponse.ts(1 hunks)src/features/home/ui/EventSliderSection.tsx(1 hunks)src/features/home/ui/EventTags.tsx(1 hunks)src/pages/home/ui/MainPage.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (3)
- src/features/home/model/eventResponse.ts
- src/features/home/ui/EventTags.tsx
- src/features/home/hooks/useEventHook.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/entities/event/model/eventRequest.ts
- src/features/event-manage/event-list/ui/EventList.tsx
- src/entities/event/api/event.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/features/home/ui/EventSliderSection.tsx (1)
src/entities/event/model/event.ts (1)
EventItem(4-14)
🔇 Additional comments (9)
src/features/home/ui/EventSliderSection.tsx (4)
1-7: 모듈 가져오기가 올바르게 구성되었습니다. 👍필요한 모든 컴포넌트와 유틸리티가 적절히 임포트되었습니다.
9-12: 인터페이스 정의가 명확합니다.
EventSliderSectionProps인터페이스가 간결하고 명확하게 정의되어 있습니다.
14-18: 컴포넌트 기본 설정이 잘 구성되었습니다.상태 관리와 내비게이션 훅이 적절히 설정되었습니다.
maxCardsToShow를 상수로 정의한 것은 좋은 접근입니다.
19-27: 네비게이션 함수 구현이 잘 되어 있습니다.순환 네비게이션을 구현하기 위한 모듈로 연산이 적절히 사용되었습니다.
src/pages/home/ui/MainPage.tsx (5)
16-17: 새로운 컴포넌트와 도구 추가가 잘 되었습니다.EventTags 컴포넌트와 ReactQueryDevtools를 가져오는 것은 좋은 변경 사항입니다.
26-26: useAuthStore에서 추가 변수 추출이 잘 되었습니다.상태 관리가 올바르게 수정되었습니다.
42-49: SecondaryButton 속성 포맷팅이 개선되었습니다.props가 더 명확하게 구성되어 가독성이 향상되었습니다.
69-71: 이벤트 표시 로직이 잘 리팩토링되었습니다.개별 이벤트 섹션을 EventTags 컴포넌트로 대체한 것은 좋은 변경 사항입니다. 코드가 더 간결해지고 유지보수성이 향상되었습니다.
80-80: React Query Devtools 추가가 개발 경험을 향상시킬 것입니다.개발 모드에서 쿼리 상태를 모니터링하기 위한 도구가 잘 추가되었습니다.
fc5e810 to
3325d6a
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/entities/event/api/event.ts (1)
74-77: updateEvent 함수가 올바르게 수정되었습니다.이전 리뷰에서 지적된 문제가 수정되어 이제 함수가 올바르게 정의되었습니다.
🧹 Nitpick comments (3)
src/entities/event/api/event.ts (3)
29-42: URL 구성 방식을 URLSearchParams로 통일하는 것이 좋습니다.현재의 문자열 템플릿 기반 URL 구성 방식은 복잡하고 오류가 발생하기 쉽습니다. URLSearchParams를 사용하면 코드가 더 명확해지고 특수 문자 처리도 안전하게 할 수 있습니다.
URLSearchParams를 사용한 개선 예시:
export const getAllEventsInfinite = async ({ page, size, tag, }: PaginationParams & { tag?: EventTag }): Promise<{ items: EventItem[]; hasNextPage: boolean }> => { - const response = await axiosClient.get<EventNormalResponse>( - `/events${tag ? `?tags=${tag}` : ''}${tag ? '&' : '?'}page=${page}&size=${size}` - ); + const params = new URLSearchParams(); + if (tag) { + params.append('tags', tag); + } + params.append('page', page.toString()); + params.append('size', size.toString()); + + const response = await axiosClient.get<EventNormalResponse>( + `/events?${params.toString()}` + ); return { items: response.data.result, hasNextPage: response.data.result.length === size, }; };
45-48: URL 구성 방식을 URLSearchParams로 통일하는 것이 좋습니다.일관성을 위해 이 함수에서도 URLSearchParams를 사용해보세요.
export const getEventByTag = async (tag: EventTag, { page, size }: PaginationParams): Promise<EventNormalResponse> => { - const response = await axiosClient.get<EventNormalResponse>(`/events?tags=${tag}&page=${page}&size=${size}`); + const params = new URLSearchParams(); + params.append('tags', tag); + params.append('page', page.toString()); + params.append('size', size.toString()); + const response = await axiosClient.get<EventNormalResponse>(`/events?${params.toString()}`); return response.data; };
51-59: URL 구성 방식을 URLSearchParams로 통일하는 것이 좋습니다.다른 함수들과의 일관성을 위해 URLSearchParams 사용을 권장합니다.
export const getEventByCategory = async ( category: EventCategory, { page, size }: PaginationParams ): Promise<EventNormalResponse> => { - const response = await axiosClient.get<EventNormalResponse>( - `/events/category?category=${category}&page=${page}&size=${size}` - ); + const params = new URLSearchParams(); + params.append('category', category); + params.append('page', page.toString()); + params.append('size', size.toString()); + const response = await axiosClient.get<EventNormalResponse>( + `/events/category?${params.toString()}` + ); return response.data; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/app/routes/Router.tsx(0 hunks)src/entities/event/api/event.ts(1 hunks)src/entities/event/model/event.ts(1 hunks)src/entities/event/model/eventMeta.ts(1 hunks)src/entities/event/model/eventRequest.ts(1 hunks)src/entities/event/model/eventResponse.ts(1 hunks)src/features/event-manage/event-list/hooks/useInfiniteScroll.ts(1 hunks)src/features/event-manage/event-list/ui/EventList.tsx(1 hunks)src/features/home/hooks/useEventHook.ts(1 hunks)src/features/home/model/eventResponse.ts(1 hunks)src/features/home/ui/EventSliderSection.tsx(1 hunks)src/features/home/ui/EventTags.tsx(1 hunks)src/pages/event/ui/AllEventsPage.tsx(2 hunks)src/pages/home/ui/MainPage.tsx(2 hunks)src/shared/types/api/http-client.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/app/routes/Router.tsx
✅ Files skipped from review due to trivial changes (1)
- src/entities/event/model/eventResponse.ts
🚧 Files skipped from review as they are similar to previous changes (12)
- src/shared/types/api/http-client.ts
- src/features/home/model/eventResponse.ts
- src/pages/event/ui/AllEventsPage.tsx
- src/features/event-manage/event-list/ui/EventList.tsx
- src/features/home/hooks/useEventHook.ts
- src/features/event-manage/event-list/hooks/useInfiniteScroll.ts
- src/features/home/ui/EventSliderSection.tsx
- src/entities/event/model/eventRequest.ts
- src/entities/event/model/eventMeta.ts
- src/entities/event/model/event.ts
- src/pages/home/ui/MainPage.tsx
- src/features/home/ui/EventTags.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/entities/event/api/event.ts (5)
src/entities/event/model/event.ts (3)
EventDetailRequest(3-5)EventItem(20-30)EventDetailResponse(7-15)src/shared/types/api/http-client.ts (1)
axiosClient(6-13)src/entities/event/model/eventMeta.ts (3)
PaginationParams(11-14)EventTag(2-2)EventCategory(3-3)src/entities/event/model/eventResponse.ts (3)
EventNormalResponse(10-10)EventDetailResponse(11-11)EventResponse(3-8)src/entities/event/model/eventRequest.ts (2)
EventCreate(20-24)EventUpdate(27-30)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: storybook
🔇 Additional comments (5)
src/entities/event/api/event.ts (5)
2-6: import 구문이 잘 정리되어 있습니다.필요한 모든 타입과 인터페이스를 적절하게 가져오고 있어 코드의 타입 안전성이 잘 보장됩니다.
62-65: getEventById 함수가 잘 구현되었습니다.eventId를 통해 이벤트 상세 정보를 가져오는 함수가 간결하고 명확하게 구현되었습니다.
68-71: createEvent 함수가 적절하게 구현되었습니다.이벤트 생성 함수가 명확하게 구현되었고, 반환 타입이 잘 지정되어 있습니다.
80-83: deleteEvent 함수가 잘 구현되었습니다.이벤트 삭제 함수가 간결하고 명확하게 구현되었습니다.
15-83:Details
✅ Verification successful
오류 처리 전략을 고려해보세요.
현재 API 함수들에는 명시적인 오류 처리가 없습니다. 전역 오류 처리 전략이 있는지 확인하고, 필요하다면 각 함수에 try-catch 블록을 추가하는 것을 고려해보세요.
백엔드 API 응답 형식과 애플리케이션의 전역 오류 처리 방식을 확인하기 위해 다음 스크립트를 실행해보세요:
🏁 Script executed:
#!/bin/bash # API 응답 처리 및 오류 처리 패턴 확인 echo "전역 오류 처리가 있는지 확인" rg -A 5 -B 5 "axios.interceptors" --type ts echo "오류 처리 관련 유틸리티 함수 확인" rg -A 3 -B 3 "catch|error|Error" --type ts ./src/shared echo "React Query 오류 처리 확인" rg -A 5 "useQuery|useMutation" --type ts ./src/featuresLength of output: 13739
전역 HTTP 오류 처리 구현 확인 (http-client.ts 인터셉터)
현재src/shared/types/api/http-client.ts의axiosClient인터셉터에서 에러(네트워크 에러, 401 토큰 리프레시 등)를 전역 처리하고 있으므로, 각 API 함수에 별도의try–catch블록을 추가하는 것은 선택사항입니다.추가 고려사항:
- React Query의
useQuery/useMutation훅에서onError옵션을 활용해 UI 수준의 에러 알림을 구현QueryClient의defaultOptions또는 React Error Boundary를 통해 전역 React Query 오류 로직 구성
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/shared/hooks/useInfiniteScroll.ts (1)
14-21: 무한 스크롤 로직이 잘 구현되었으나 몇 가지 개선사항이 있습니다.코드는 기본적으로 잘 작성되었지만, 다음 사항들을 고려해 보세요:
lastPage.hasNextPage가 undefined인 경우에 대한 예외 처리- API 응답 구조가 변경될 경우를 대비한 방어적 코딩
- 에러 처리 로직 추가
export const useInfiniteScroll = <T>({ queryKey, queryFn, size = 10, filters }: UseInfiniteScrollProps<T>) => { return useInfiniteQuery({ queryKey, queryFn: ({ pageParam = 0 }) => queryFn({ page: pageParam, size, ...filters }), - getNextPageParam: (lastPage, allPages) => (lastPage.hasNextPage ? allPages.length : undefined), + getNextPageParam: (lastPage, allPages) => (lastPage?.hasNextPage === true ? allPages.length : undefined), initialPageParam: 0, + // 추가 옵션 + // retry: 1, // API 호출 실패 시 재시도 횟수 + // staleTime: 5 * 60 * 1000, // 5분 동안 데이터를 신선하게 유지 }); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/entities/event/api/event.ts(1 hunks)src/entities/event/model/event.ts(2 hunks)src/features/dashboard/model/event.ts(1 hunks)src/features/event-manage/event-create/api/event.ts(1 hunks)src/features/event-manage/event-create/hooks/useEventHook.ts(1 hunks)src/features/event-manage/event-create/model/FunnelContext.tsx(1 hunks)src/features/event-manage/event-create/model/event.ts(1 hunks)src/features/event-manage/event-list/ui/EventList.tsx(1 hunks)src/features/home/hooks/useEventHook.ts(1 hunks)src/features/home/ui/EventSliderSection.tsx(1 hunks)src/features/home/ui/EventTags.tsx(1 hunks)src/shared/hooks/useInfiniteScroll.ts(1 hunks)src/shared/types/baseEventType.ts(1 hunks)
✅ Files skipped from review due to trivial changes (6)
- src/features/event-manage/event-create/model/FunnelContext.tsx
- src/features/event-manage/event-create/hooks/useEventHook.ts
- src/features/event-manage/event-create/model/event.ts
- src/features/event-manage/event-create/api/event.ts
- src/shared/types/baseEventType.ts
- src/features/dashboard/model/event.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- src/features/home/ui/EventTags.tsx
- src/features/event-manage/event-list/ui/EventList.tsx
- src/features/home/hooks/useEventHook.ts
- src/entities/event/model/event.ts
- src/features/home/ui/EventSliderSection.tsx
- src/entities/event/api/event.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/shared/hooks/useInfiniteScroll.ts (1)
src/entities/event/model/event.ts (2)
PaginationParams(18-21)EventFilters(23-27)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: storybook
🔇 Additional comments (2)
src/shared/hooks/useInfiniteScroll.ts (2)
4-12: 인터페이스 설계가 잘 되었습니다.제네릭 타입을 활용한 인터페이스 설계로 다양한 데이터 타입에 재사용할 수 있는 유연한 구조를 제공합니다. 필수 속성과 선택적 속성이 명확하게 구분되어 있어 사용하기 편리합니다.
1-21: 전반적인 hook 설계가 우수합니다.이 무한 스크롤 hook은 다음과 같은 장점이 있습니다:
- 제네릭 타입을 활용하여 다양한 데이터 타입에 사용 가능
useInfiniteQuery를 효과적으로 추상화하여 반복 코드 감소- 페이지네이션과 필터링을 단순화하는 직관적인 API 제공
- 기본값을 통한 사용 편의성 제공
메인 페이지 및 이벤트 목록 페이지에서 이 hook을 활용하면 코드의 일관성과 유지보수성이 향상될 것입니다.
a8dde73 to
5bc5732
Compare
메인 페이지 태그별 이벤트 불러오기
최신 이벤트
요즘 뜨는 이벤트
곧 이벤트가 마감되요!
전체 이벤트 보러가기
기타 사항
LoginModal.tsx에서 소셜 로그인 URL에서 / 가 겹침 ->.env파일 수정함develop브랜치 변경사항을feat/#101/event-check-api브랜치에 rebase함features/home/ui/EventTags.tsx파일 생성 ->MainPage.tsx파일에서 호출React Query Devtools를App()최상단에서 사용해도 되는지 궁금함요Summary by CodeRabbit
신규 기능
버그 수정
문서화