Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
"dependencies": {
"@hello-pangea/dnd": "^18.0.1",
"@hookform/resolvers": "^4.1.3",
"@tanstack/react-query": "^5.61.3",
"@tanstack/react-query": "^5.72.0",
"autoprefixer": "^10.4.20",
"axios": "^1.8.1",
"axios": "^1.8.4",
"date-fns": "^4.1.0",
"framer-motion": "^12.4.7",
"js-cookie": "^3.0.5",
Expand Down Expand Up @@ -49,6 +49,7 @@
"@storybook/react": "^8.4.6",
"@storybook/react-vite": "^8.4.6",
"@storybook/test": "^8.4.6",
"@types/axios": "^0.14.4",
"@types/js-cookie": "^3.0.6",
"@types/lodash": "^4.17.13",
"@types/node": "^22.10.5",
Expand Down
122 changes: 108 additions & 14 deletions src/pages/event/ui/AllEventsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,93 @@
import { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import SecondaryButton from '../../../../design-system/ui/buttons/SecondaryButton';
import Header from '../../../../design-system/ui/Header';
import SearchTextField from '../../../../design-system/ui/textFields/SearchTextField';
import searchIcon from '../../../../design-system/icons/Search.svg';
import BottomBar from '../../../widgets/main/ui/BottomBar';
import EventCard from '../../../shared/ui/EventCard';
import { trendingEvents } from '../../../shared/types/eventCardType';
import { useNavigate } from 'react-router-dom';
// import { trendingEvents } from '../../../shared/types/eventCardType';
import { eventApi } from '../../../shared/api/eventApi';
import { EventItem, EventNormalResponse } from '../../../shared/types/api/event';

const AllEventsPage = () => {
const navigater = useNavigate();
const [events, setEvents] = useState<EventItem[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [page, setPage] = useState<number>(0);
const [hasMore, setHasMore] = useState<boolean>(true);
const observer = useRef<IntersectionObserver | null>(null);
const loadingRef = useRef<HTMLDivElement>(null);

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);
}
};
Comment on lines +23 to +63
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

loadEvents 함수에 몇 가지 개선 사항이 필요합니다.

이벤트를 불러오는 함수가 잘 구현되어 있지만, 몇 가지 개선할 점이 있습니다:

  1. 불필요한 console.log 문이 많이 포함되어 있습니다. 프로덕션 코드에서는 제거하는 것이 좋습니다.
  2. 에러 처리 시 더 구체적인 에러 메시지를 표시하면 디버깅에 도움이 될 것입니다.
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.

Suggested change
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);
}
};


const lastEventRef = useCallback(
(node: HTMLDivElement) => {
if (isLoading || !hasMore) return;

if (observer.current) observer.current.disconnect();

observer.current = new IntersectionObserver(entries => {
if (entries[0].isIntersecting && hasMore) {
console.log('Loading next page:', page + 1);
loadEvents(page + 1);
}
});

if (node) observer.current.observe(node);
},
[isLoading, hasMore, page]
);

useEffect(() => {
loadEvents(0);
return () => {
if (observer.current) {
observer.current.disconnect();
}
};
}, []);

return (
<div className="flex flex-col items-center mb-28">
Expand All @@ -26,23 +105,38 @@ const AllEventsPage = () => {
leftButtonLabel="같이가요"
rightContent={<SecondaryButton size="large" color="black" label="로그인" onClick={() => {}} />}
/>
{/* 이벤트 카드 목록 */}
<div className="grid grid-cols-2 gap-4 mx-6 mt-2 md:grid-cols-2 lg:grid-cols-2">
{trendingEvents.map((event, index) => (
<EventCard
key={index}
img={event.img}
eventTitle={event.eventTitle}
dDay={event.dDay}
host={event.host}
eventDate={event.eventDate}
location={event.location}
hashtags={event.hashtags}
/>
{events.map((event, index) => (
<div key={event.id} ref={index === events.length - 1 ? lastEventRef : undefined}>
<EventCard
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={() => navigater(`/event/${event.id}`)}
/>
</div>
))}
</div>
{isLoading && (
<div className="text-center p-4" ref={loadingRef}>
이벤트 불러오는 중...ㅎ
</div>
)}
{error && <div className="text-center p-4 text-red-500">{error}</div>}
{!hasMore && !isLoading && events.length > 0 && (
<div className="text-center p-4 text-gray-500">더 이상 표시할 이벤트가 없습니다.</div>
)}
{!isLoading && events.length === 0 && (
<div className="text-center p-4 text-gray-500">표시할 이벤트가 없습니다.</div>
)}
<BottomBar />
</div>
);
};

export default AllEventsPage;
Loading