-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 검색 페이지 API 연동 #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 검색 페이지 API 연동 #122
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { EventList } from '../../../features/event-manage/event-list/model/eventList'; | ||
| import { useInfiniteScroll } from '../../../shared/hooks/useInfiniteScroll'; | ||
| import { getAllEventsInfinite } from '../api/event'; | ||
|
|
||
| const useEventList = () => { | ||
| const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteScroll<EventList>({ | ||
| queryKey: ['events', 'infinite'], | ||
| queryFn: getAllEventsInfinite, | ||
| size: 10, | ||
| filters: { tag: 'current' }, | ||
| }); | ||
| return { data, fetchNextPage, hasNextPage, isFetching }; | ||
| }; | ||
| export default useEventList; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import { BaseEvent } from '../../../../shared/types/baseEventType'; | ||
|
|
||
| export interface EventList extends BaseEvent { | ||
| id: number; | ||
| hostChannelName: string; | ||
| remainDays: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,19 +7,17 @@ import firstPage from '../../../../public/assets/banners/1.png'; | |
| import secondPage from '../../../../public/assets/banners/2.png'; | ||
| import thirdPage from '../../../../public/assets/banners/3.png'; | ||
| import EventCard from '../../../shared/ui/EventCard'; | ||
| import { trendingEventsData } from '../../../shared/types/eventCardType'; | ||
| import { hostInfoData } from '../../../shared/types/hostInfoType'; | ||
| import { FilterDataType } from '../../../shared/types/filterDataType'; | ||
| import { FilterMockData } from '../../../shared/types/filterDataType'; | ||
| import ProfileCircle from '../../../../design-system/ui/Profile'; | ||
| import useEventList from '../../../entities/event/hook/useEventListHook'; | ||
| import type { EventList } from '../../../features/event-manage/event-list/model/eventList'; | ||
| import useHostChannelList from '../../../entities/host/hook/useHostChannelListHook'; | ||
|
|
||
| const SearchPage = () => { | ||
| const [keyword, setKeyword] = useState(''); | ||
| const [filterData, setFilterDate] = useState<FilterDataType>({ | ||
| Events: [], | ||
| Host: [], | ||
| }); | ||
| //@TODO:추후에 response body 보고 Type 수정 | ||
| const { data, hasNextPage, isFetching, fetchNextPage } = useEventList(); | ||
| const { data: hostData } = useHostChannelList(); | ||
| const observerRef = useRef<IntersectionObserver>(); | ||
| const lastEventCardRef = useRef<HTMLDivElement | null>(null); | ||
|
|
||
| const images = [ | ||
| { img: firstPage, link: 'https://example.com/page1' }, | ||
|
|
@@ -36,11 +34,23 @@ const SearchPage = () => { | |
| ]; | ||
|
|
||
| useEffect(() => { | ||
| //@TODO:API 호출 후, response를 setFilterDate에 넣을 예정 | ||
| //현재는 목업 데이터를 넣어놓음 | ||
| //@TODO:API 연동하며 디바운스 구현 예정 | ||
| setFilterDate(FilterMockData); | ||
| }, [keyword]); | ||
| if (!hasNextPage || isFetching) return; | ||
| if (observerRef.current) observerRef.current.disconnect(); | ||
|
|
||
| observerRef.current = new IntersectionObserver(entries => { | ||
| if (entries[0].isIntersecting && hasNextPage) { | ||
| fetchNextPage(); | ||
| } | ||
| }); | ||
|
|
||
| if (lastEventCardRef.current) observerRef.current.observe(lastEventCardRef.current); | ||
|
|
||
| return () => { | ||
| if (observerRef.current) { | ||
| observerRef.current.disconnect(); | ||
| } | ||
| }; | ||
| }, [hasNextPage, isFetching, fetchNextPage]); | ||
|
|
||
| const navigate = useNavigate(); | ||
| const inputRef = useRef<HTMLInputElement | null>(null); // Input 요소를 참조하기 위한 훅 | ||
|
|
@@ -75,49 +85,68 @@ const SearchPage = () => { | |
| {keyword ? ( | ||
| <> | ||
| <div className="px-6 flex flex-col gap-8"> | ||
| {/* 이벤트 검색 결과를 렌더링 하는 부분 */} | ||
| {filterData.Events?.length > 0 && ( | ||
| <div> | ||
| <p className="font-bold text-lg lg:text-xl mb-3">이벤트</p> | ||
| <div className="grid grid-cols-2 gap-4"> | ||
| {filterData.Events?.map((event: trendingEventsData) => ( | ||
| <EventCard | ||
| key={event.id} | ||
| img={event.img} | ||
| eventTitle={event.eventTitle} | ||
| dDay={event.dDay} | ||
| host={event.host} | ||
| eventDate={event.eventDate} | ||
| location={event.location} | ||
| hashtags={event.hashtags} | ||
| /> | ||
| ))} | ||
| </div> | ||
| <div> | ||
| <p className="font-bold text-lg lg:text-xl mb-3">이벤트</p> | ||
| <div className="grid grid-cols-2 gap-4"> | ||
| {data?.pages.map((page, pageIndex) => | ||
| page.items | ||
| .filter( | ||
| (event: EventList) => | ||
| event.title.toLowerCase().includes(keyword.toLowerCase()) || | ||
| event.address.toLowerCase().includes(keyword.toLowerCase()) || | ||
| event.hostChannelName.toLowerCase().includes(keyword.toLowerCase()) | ||
| ) | ||
| .map((event: EventList, 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>} | ||
| </div> | ||
|
|
||
| {/* 호스트 검색 결과를 렌더링 하는 부분 */} | ||
| {filterData.Host?.length > 0 && ( | ||
| <div> | ||
| <p className="font-bold pb-3 text-lg lg:text-xl mb-3">호스트</p> | ||
| <div className="flex flex-wrap gap-9 px-2"> | ||
| {filterData.Host?.map((host: hostInfoData) => ( | ||
| <div> | ||
| <p className="font-bold pb-3 text-lg lg:text-xl mb-3">호스트</p> | ||
| <div className="flex flex-wrap gap-9 px-2 mb-10"> | ||
| {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> | ||
|
Comment on lines
+125
to
137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
- {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 |
||
| )} | ||
| </div> | ||
| </div> | ||
|
|
||
| {!filterData.Host?.length && !filterData.Events?.length && ( | ||
| <div className="p-6 text-center font-semibold text-gray-700">검색 결과가 없습니다.</div> | ||
| )} | ||
| {!hostData?.result.some(host => host.hostChannelName.toLowerCase().includes(keyword.toLowerCase())) && | ||
| !data?.pages.some(page => | ||
| page.items.some( | ||
| event => | ||
| event.title.toLowerCase().includes(keyword.toLowerCase()) || | ||
| event.address.toLowerCase().includes(keyword.toLowerCase()) || | ||
| event.hostChannelName.toLowerCase().includes(keyword.toLowerCase()) | ||
| ) | ||
| ) && <div className="p-6 text-center font-semibold text-gray-700">검색 결과가 없습니다.</div>} | ||
| </> | ||
| ) : ( | ||
| <div className="px-6"> | ||
|
|
||
There was a problem hiding this comment.
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)는 훅의 재사용성을 제한합니다. 다양한 상황에서 활용할 수 있도록 매개변수를 받도록 개선하는 것이 좋겠습니다.📝 Committable suggestion