Skip to content

feat: 검색 페이지 API 연동#122

Merged
Yejiin21 merged 3 commits intodevelopfrom
feat/#120/search-page-api
May 13, 2025
Merged

feat: 검색 페이지 API 연동#122
Yejiin21 merged 3 commits intodevelopfrom
feat/#120/search-page-api

Conversation

@Yejiin21
Copy link
Copy Markdown
Contributor

@Yejiin21 Yejiin21 commented May 12, 2025

ToDo

  • 메인페이지 로그인시 버튼 UI 변경
  • 검색페이지 이벤트리스트, 호스트 정보 API 연동

이슈 이외에 ToDo

  • 이벤트 리스트 API hook파일과 데이터 타입 따로 파일로 분리

추가 작업

  • 인기검색어 API 완성이 안된 상태라, 추후에 새로 이슈 생성하여 작업 할 예정

Summary by CodeRabbit

  • 신규 기능

    • 이벤트 목록에 무한 스크롤 기능이 추가되어, 이벤트를 스크롤할 때 자동으로 더 많은 데이터를 불러올 수 있습니다.
    • 검색 페이지에서 이벤트와 호스트 데이터를 실시간으로 불러오며, 검색 키워드에 따라 결과가 동적으로 필터링됩니다.
  • 리팩터

    • 이벤트 목록 및 검색 페이지의 데이터 처리 로직이 API 기반의 비동기 방식으로 개선되었습니다.
    • 헤더의 로그인 영역이 프로필 표시 또는 로그인 버튼으로 변경되어 사용자 경험이 향상되었습니다.

@Yejiin21 Yejiin21 requested review from hyeeuncho and xaexunxang May 12, 2025 03:19
@Yejiin21 Yejiin21 self-assigned this May 12, 2025
@Yejiin21 Yejiin21 added the 🔧 Feature 기능 구현 label May 12, 2025
@Yejiin21 Yejiin21 linked an issue May 12, 2025 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented May 12, 2025

Walkthrough

이 변경사항은 이벤트 목록의 무한 스크롤 및 페이징 처리를 위한 커스텀 훅(useEventList)을 도입하고, 기존의 목업 데이터를 동적 API 데이터로 대체하며, 검색 및 메인 페이지에서 해당 훅을 활용하도록 리팩토링합니다. 새로운 타입 정의와 UI 컴포넌트의 조건부 렌더링 개선도 포함됩니다.

Changes

파일/경로 변경 요약
src/entities/event/hook/useEventListHook.ts 이벤트 목록 무한 스크롤 및 페이징 처리를 위한 커스텀 훅 useEventList 추가.
src/features/event-manage/event-list/model/eventList.ts BaseEvent를 확장하는 EventList 타입 정의(id, hostChannelName, remainDays 속성 추가).
src/features/event-manage/event-list/ui/EventList.tsx 기존 무한 스크롤 훅 및 직접 API 호출 로직을 useEventList 훅 사용으로 교체. 타입 및 import 정리.
src/pages/home/ui/MainPage.tsx 헤더 우측 콘텐츠를 로그인 상태에 따라 ProfileCircle 또는 로그인 버튼으로 조건부 렌더링하도록 변경.
src/pages/search/ui/SearchPage.tsx 목업 데이터 제거, useEventList/useHostChannelList 사용, 이벤트 무한 스크롤 및 검색 필터링 로직 적용.

Sequence Diagram(s)

sequenceDiagram
    participant UI as EventList/SearchPage UI
    participant Hook as useEventList
    participant API as getAllEventsInfinite

    UI->>Hook: useEventList() 호출
    Hook->>API: getAllEventsInfinite({ page, filter })
    API-->>Hook: 이벤트 페이지 데이터 반환
    Hook-->>UI: { data, fetchNextPage, hasNextPage, isFetching }
    UI->>Hook: fetchNextPage() (스크롤 하단 도달 시)
    Hook->>API: getAllEventsInfinite(다음 페이지)
    API-->>Hook: 다음 이벤트 페이지 데이터 반환
    Hook-->>UI: 갱신된 데이터
Loading

Possibly related PRs

Poem

🐰
이벤트가 쏟아진다, 무한한 스크롤~
목업은 안녕, API로 채운다!
프로필 동그라미, 로그인 버튼 반짝
검색도 실시간, 토끼는 신이 나
코드는 정갈하게, 변화는 신속하게!
🥕✨

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

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

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this 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 Markdown

Copy link
Copy Markdown

@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: 2

🔭 Outside diff range comments (1)
src/features/event-manage/event-list/ui/EventList.tsx (1)

33-55: 🛠️ Refactor suggestion

데이터 불러오기 상태에 대한 처리가 필요합니다.

현재 코드는 데이터가 로딩 중일 때 전체 그리드를 렌더링하지만, data가 undefined인 초기 상태에 대한 처리가 누락되어 있습니다. 로딩 상태에 대한 명시적인 처리를 추가하는 것이 좋겠습니다.

return (
  <>
+   {!data && <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) =>
🧹 Nitpick comments (4)
src/pages/home/ui/MainPage.tsx (1)

44-48: 로그인 상태에 따른 UI 개선이 적절합니다.

로그인 상태에 따라 다른 컴포넌트를 표시하는 조건부 렌더링이 잘 구현되었습니다. 다만, 몇 가지 개선 사항을 제안합니다:

  1. ProfileCircle에 고정된 "userProfile" 값 대신 실제 사용자 프로필 이미지를 활용하는 것이 좋겠습니다.
  2. name?.slice(1, 3)는 이름이 짧은 경우(한 글자) 문제가 될 수 있습니다. 이름 길이에 따른 조건부 처리를 고려해보세요.
- <ProfileCircle profile="userProfile" name={name?.slice(1, 3) || ''} className="w-11 h-11 text-15" />
+ <ProfileCircle 
+   profile={userProfile || "userProfile"} 
+   name={name ? (name.length > 1 ? name.slice(1, 3) : name) : ''} 
+   className="w-11 h-11 text-15" 
+ />
src/features/event-manage/event-list/ui/EventList.tsx (2)

4-5: 임포트 구조가 적절합니다.

필요한 훅과 타입을 적절히 임포트했습니다. 다만 컴포넌트와 타입 이름이 동일하여 정적 분석 도구에서 경고가 발생했습니다. 타입 이름에 접미사를 추가하는 방식으로 구분하는 것이 좋습니다.

- import type { EventList } from '../model/eventList';
+ import type { EventList as EventListType } from '../model/eventList';

12-12: 개발용 콘솔 로그를 제거해주세요.

프로덕션 코드에는 디버깅용 콘솔 로그를 남겨두지 않는 것이 좋습니다.

- console.log('EventList data.pages:', data?.pages);
src/pages/search/ui/SearchPage.tsx (1)

93-99: toLowerCase() 반복 호출을 줄여 가독성과 성능을 개선하세요

같은 keyword.toLowerCase() 와 각 필드의 toLowerCase() 를 루프마다 세 번씩 호출하고 있습니다. 한 번만 소문자로 변환해 두고 비교하면 더 간결하며, 대규모 데이터셋에서도 약간의 성능 이점을 얻을 수 있습니다.

- .filter(
-   (event: EventList) =>
-     event.title.toLowerCase().includes(keyword.toLowerCase()) ||
-     event.address.toLowerCase().includes(keyword.toLowerCase()) ||
-     event.hostChannelName.toLowerCase().includes(keyword.toLowerCase())
- )
+ .filter((event: EventList) => {
+   const lower = keyword.toLowerCase();
+   return (
+     event.title.toLowerCase().includes(lower) ||
+     event.address.toLowerCase().includes(lower) ||
+     event.hostChannelName.toLowerCase().includes(lower)
+   );
+ })

같은 방식으로 145-147행의 some 조건도 수정해 주세요.

Also applies to: 145-147

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 92c43d1 and ee093d0.

📒 Files selected for processing (5)
  • src/entities/event/hook/useEventListHook.ts (1 hunks)
  • src/features/event-manage/event-list/model/eventList.ts (1 hunks)
  • src/features/event-manage/event-list/ui/EventList.tsx (2 hunks)
  • src/pages/home/ui/MainPage.tsx (2 hunks)
  • src/pages/search/ui/SearchPage.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/features/event-manage/event-list/model/eventList.ts (1)
src/shared/types/baseEventType.ts (1)
  • BaseEvent (5-24)
src/entities/event/hook/useEventListHook.ts (3)
src/shared/hooks/useInfiniteScroll.ts (1)
  • useInfiniteScroll (14-21)
src/features/event-manage/event-list/model/eventList.ts (1)
  • EventList (3-7)
src/entities/event/api/event.ts (1)
  • getAllEventsInfinite (28-44)
src/features/event-manage/event-list/ui/EventList.tsx (1)
src/features/event-manage/event-list/model/eventList.ts (1)
  • EventList (3-7)
src/pages/search/ui/SearchPage.tsx (1)
src/features/event-manage/event-list/model/eventList.ts (1)
  • EventList (3-7)
🪛 Biome (1.9.4)
src/features/event-manage/event-list/ui/EventList.tsx

[error] 7-7: Shouldn't redeclare 'EventList'. Consider to delete it or rename it.

'EventList' is defined here:

(lint/suspicious/noRedeclare)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: storybook
🔇 Additional comments (6)
src/features/event-manage/event-list/model/eventList.ts (1)

1-7: 타입 정의가 명확하고 적절합니다.

BaseEvent를 확장하여 이벤트 목록에 필요한 추가 속성들을 잘 정의하였습니다. id, hostChannelName, remainDays 속성들은 이벤트 목록 UI에 필요한 정보들을 포함하고 있습니다.

src/pages/home/ui/MainPage.tsx (1)

17-17: ProfileCircle 컴포넌트 추가 확인

새로운 프로필 컴포넌트를 추가하여 UI 개선을 수행했습니다.

src/entities/event/hook/useEventListHook.ts (1)

1-4: 필요한 임포트들이 잘 정의되어 있습니다.

이벤트 목록 기능 구현에 필요한 타입과 훅, API 함수를 적절히 임포트했습니다.

src/features/event-manage/event-list/ui/EventList.tsx (2)

8-8: 커스텀 훅 사용이 잘 구현되었습니다.

기존의 인라인 infinite scroll 로직을 커스텀 훅으로 추출하여 코드가 더 간결해졌습니다.


37-37: 타입 적용이 올바르게 되었습니다.

이벤트 아이템의 타입이 올바르게 EventList로 지정되었습니다. 이를 통해 IDE의 타입 힌트와 자동완성 기능을 활용할 수 있습니다.

src/pages/search/ui/SearchPage.tsx (1)

36-53: IntersectionObserver 재생성 로직 확인 권고

observerRef.current 를 매 렌더마다 새로 생성/해제하고 있는데, lastEventCardRef.current 가 아직 설정되지 않은 첫 렌더에서 옵저버가 등록되지 않을 수 있습니다. 필요한 경우

  1. if (!lastEventCardRef.current) return; 로 빠르게 종료하거나
  2. useCallback ref 로 마지막 카드 요소가 바뀔 때마다 옵저버를 재등록하는 방식도 고려해 보세요.

큰 문제는 아니지만 빠른 스크롤 상황에서 페치가 지연될 가능성을 줄일 수 있습니다.

Comment on lines +5 to +13
const useEventList = () => {
const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteScroll<EventList>({
queryKey: ['events', 'infinite'],
queryFn: getAllEventsInfinite,
size: 10,
filters: { tag: 'current' },
});
return { data, fetchNextPage, hasNextPage, isFetching };
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

커스텀 훅의 재사용성 개선이 필요합니다.

이벤트 목록을 가져오는 훅이 잘 구현되었지만, 하드코딩된 필터 값({ tag: 'current' })과 고정된 사이즈(10)는 훅의 재사용성을 제한합니다. 다양한 상황에서 활용할 수 있도록 매개변수를 받도록 개선하는 것이 좋겠습니다.

- const useEventList = () => {
+ const useEventList = (options = { size: 10, tag: 'current' }) => {
  const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteScroll<EventList>({
    queryKey: ['events', 'infinite'],
    queryFn: getAllEventsInfinite,
-   size: 10,
-   filters: { tag: 'current' },
+   size: options.size,
+   filters: { tag: options.tag },
  });
  return { data, fetchNextPage, hasNextPage, isFetching };
};
📝 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 useEventList = () => {
const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteScroll<EventList>({
queryKey: ['events', 'infinite'],
queryFn: getAllEventsInfinite,
size: 10,
filters: { tag: 'current' },
});
return { data, fetchNextPage, hasNextPage, isFetching };
};
const useEventList = (options = { size: 10, tag: 'current' }) => {
const { data, fetchNextPage, hasNextPage, isFetching } =
useInfiniteScroll<EventList>({
queryKey: ['events', 'infinite'],
queryFn: getAllEventsInfinite,
size: options.size,
filters: { tag: options.tag },
});
return { data, fetchNextPage, hasNextPage, isFetching };
};

Comment on lines +125 to 137
{hostData?.result
.filter(host => host.hostChannelName.toLowerCase().includes(keyword.toLowerCase()))
.map(host => (
<ProfileCircle
key={host.id}
profile="hostInfoProfile"
name={host.name}
id={host.id}
profile="hostInfoProfile"
name={host.hostChannelName}
onClick={() => navigate(`/menu/hostInfo/${host.id}`)}
className="w-19 h-19 md:w-20 md:h-20 text-sm md:text-16 lg:text-base"
/>
))}
</div>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

hostData?.result 접근 시 null-safe 체인이 빠져 런타임 오류가 발생합니다

hostData 가 아직 로딩 중이거나 에러로 인해 undefined 인 경우, hostData?.resultundefined 를 반환합니다. 그럼에도 .filter / .some 메서드를 바로 호출하기 때문에 “Cannot read properties of undefined (reading 'filter')” 와 같은 예외가 발생할 수 있습니다.
아래처럼 result 에도 optional chaining 을 추가하여 방어 코드를 적용해 주세요.

- {hostData?.result
-   .filter(host => host.hostChannelName.toLowerCase().includes(keyword.toLowerCase()))
+ {hostData?.result?.filter(
+     host => host.hostChannelName.toLowerCase().includes(keyword.toLowerCase())
+   )
- {!hostData?.result.some(host =>
+ {!hostData?.result?.some(host =>

Also applies to: 141-149

Copy link
Copy Markdown
Member

@hyeeuncho hyeeuncho left a comment

Choose a reason for hiding this comment

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

수고하셨습니다

@Yejiin21 Yejiin21 merged commit 0649a61 into develop May 13, 2025
2 checks passed
@Yejiin21 Yejiin21 deleted the feat/#120/search-page-api branch May 13, 2025 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔧 Feature 기능 구현

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 검색 페이지 API 연동

2 participants