From 33e507dd7187de622aefdb7c9d8ad4d2180e57b6 Mon Sep 17 00:00:00 2001 From: Hyeonjun0527 Date: Wed, 21 Jan 2026 13:10:04 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=A0=84=ED=99=98?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=EB=A7=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(service)/home/home-content.tsx | 89 ++ src/app/(service)/home/page.tsx | 15 +- src/components/home/tab-navigation.tsx | 78 ++ src/components/home/tabs/archive-tab.tsx | 795 ++++++++++++++++++ src/components/home/tabs/community-tab.tsx | 197 +++++ src/components/home/tabs/hall-of-fame-tab.tsx | 530 ++++++++++++ src/components/home/tabs/study-tab.tsx | 12 + src/widgets/home/sidebar.tsx | 10 +- 8 files changed, 1715 insertions(+), 11 deletions(-) create mode 100644 src/app/(service)/home/home-content.tsx create mode 100644 src/components/home/tab-navigation.tsx create mode 100644 src/components/home/tabs/archive-tab.tsx create mode 100644 src/components/home/tabs/community-tab.tsx create mode 100644 src/components/home/tabs/hall-of-fame-tab.tsx create mode 100644 src/components/home/tabs/study-tab.tsx diff --git a/src/app/(service)/home/home-content.tsx b/src/app/(service)/home/home-content.tsx new file mode 100644 index 00000000..c910c7e4 --- /dev/null +++ b/src/app/(service)/home/home-content.tsx @@ -0,0 +1,89 @@ +'use client'; + +import { Suspense } from 'react'; +import { useSearchParams } from 'next/navigation'; +import dynamic from 'next/dynamic'; +import Banner from '@/widgets/home/banner'; +import StudyCard from '@/features/study/schedule/ui/study-card'; +import TabNavigation from '@/components/home/tab-navigation'; + +// 탭 컴포넌트들을 동적으로 로드 (성능 최적화) +const StudyTab = dynamic(() => import('@/components/home/tabs/study-tab'), { + loading: () => ( +
+ + +
+ ), + ssr: false +}); + +const HallOfFameTab = dynamic(() => import('@/components/home/tabs/hall-of-fame-tab'), { + loading: () =>
로딩 중...
, + ssr: false +}); + +const ArchiveTab = dynamic(() => import('@/components/home/tabs/archive-tab'), { + loading: () =>
로딩 중...
, + ssr: false +}); + +const CommunityTab = dynamic(() => import('@/components/home/tabs/community-tab'), { + loading: () =>
로딩 중...
, + ssr: false +}); + +function HomeContentInner() { + const searchParams = useSearchParams(); + const activeTab = searchParams?.get('tab') || 'study'; // 기본값을 'study'로 설정 + + // 이제 항상 탭 시스템을 사용 + const renderTabContent = () => { + switch (activeTab) { + case 'study': + return ; + case 'ranking': + return ; + case 'archive': + return ; + case 'community': + return ; + default: + // 알 수 없는 탭이면 기본값으로 폴백 + return ; + } + }; + + return ( + <> + {/* 탭 네비게이션 */} + + + {/* 탭 콘텐츠 */} + + 로딩 중... + + } + > + {renderTabContent()} + + + ); +} + +export default function HomeContent() { + return ( + + + + + } + > + + + ); +} diff --git a/src/app/(service)/home/page.tsx b/src/app/(service)/home/page.tsx index 0e2b8815..dd28de4b 100644 --- a/src/app/(service)/home/page.tsx +++ b/src/app/(service)/home/page.tsx @@ -1,8 +1,10 @@ import { Metadata } from 'next'; +import { Suspense } from 'react'; import StudyCard from '@/features/study/schedule/ui/study-card'; import { generateMetadata as generateSEOMetadata } from '@/utils/seo'; import Banner from '@/widgets/home/banner'; import Sidebar from '@/widgets/home/sidebar'; +import HomeContent from './home-content'; export const metadata: Metadata = generateSEOMetadata({ title: '홈 - ZERO-ONE', @@ -17,8 +19,17 @@ export default async function Home() { return (
- - + {/* 기존 기능을 100% 보존하면서 새로운 탭 시스템 추가 */} + + + + + } + > + +
+ } + /> + ); +}; + +// ---------------------------------------------------------------------- +// Main Component +// ---------------------------------------------------------------------- + +export default function HallOfFameTab() { + const [rankingType, setRankingType] = useState('ATTENDANCE'); + const [rankers, setRankers] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [currentPage, setCurrentPage] = useState(1); + const [searchTerm, setSearchTerm] = useState(''); + const [jobFilter, setJobFilter] = useState(''); + + const ITEMS_PER_PAGE = 15; + + // Data Loading Simulation + useEffect(() => { + setIsLoading(true); + setCurrentPage(1); + + const timer = setTimeout(() => { + const data = Array.from({ length: 100 }, (_, i) => { + return generateMockRankers(rankingType).map((r) => ({ + ...r, + rank: r.rank + i * 20, + })); + }) + .flat() + .map((item, index) => ({ ...item, rank: index + 1 })); + setRankers(data); + setIsLoading(false); + }, 400); + + return () => clearTimeout(timer); + }, [rankingType]); + + // Filtering Logic + const filteredRankers = rankers.filter((r) => { + const matchesSearch = r.nickname + .toLowerCase() + .includes(searchTerm.toLowerCase()); + const matchesJob = jobFilter ? r.major === jobFilter : true; + return matchesSearch && matchesJob; + }); + + // Pagination Logic + const totalItems = filteredRankers.length; + const totalPages = Math.ceil(Math.max(0, totalItems - 3) / ITEMS_PER_PAGE); + + const currentRankers = filteredRankers + .slice(3) + .slice( + (currentPage - 1) * ITEMS_PER_PAGE, + currentPage * ITEMS_PER_PAGE, + ); + + return ( +
+ {/* Header Area */} +
+

+ 명예의 전당 + +

+
+ + {/* Filters & Search */} +
+
+ {(Object.keys(TAB_CONFIG) as RankingType[]).map((type) => ( + + ))} +
+ +
+
+ + +
+ setSearchTerm(e.target.value)} + className="h-600 w-full rounded-100 border border-border-subtle bg-background-default pl-200 pr-500 font-designer-14m outline-none focus:border-border-default focus:ring-2 focus:ring-fill-neutral-default-default transition-all" + /> + + + +
+
+
+
+ + {isLoading ? ( +
+ +
데이터를 불러오는 중입니다...
+
+ ) : ( + <> + {/* Top 3 Section */} + {filteredRankers.length > 0 && ( +
+ {filteredRankers[1] && ( +
+ +
+ )} + {filteredRankers[0] && ( +
+ +
+ )} + {filteredRankers[2] && ( +
+ +
+ )} +
+ )} + + {/* Ranking Table */} +
+
+
Rank
+
Member
+
Score
+
Activity
+
+ +
+ {currentRankers.map((ranker) => ( + +
+ + {ranker.rank} + + +
+ +
+ +
+
+ {ranker.nickname} +
+
+ {ranker.major} +
+
+
+ +
+
+ {ranker.scoreLabel} +
+
+ 상위 1% +
+
+ +
+
{ranker.studyTime} 누적
+
+ 최근: {ranker.lastActive} +
+
+
+ } + /> + ))} +
+
+ + )} + + {/* Pagination */} + {totalPages > 1 && ( +
+ + + {currentPage} / {totalPages} + + +
+ )} + + ); +} diff --git a/src/components/home/tabs/study-tab.tsx b/src/components/home/tabs/study-tab.tsx new file mode 100644 index 00000000..204af9ca --- /dev/null +++ b/src/components/home/tabs/study-tab.tsx @@ -0,0 +1,12 @@ +import Banner from '@/widgets/home/banner'; +import StudyCard from '@/features/study/schedule/ui/study-card'; + +export default function StudyTab() { + return ( +
+ {/* 기존 컴포넌트들을 그대로 사용 - 100% 안전 */} + + +
+ ); +} diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx index 7f4653e8..15d882a5 100644 --- a/src/widgets/home/sidebar.tsx +++ b/src/widgets/home/sidebar.tsx @@ -36,15 +36,7 @@ export default async function Sidebar() { sincerityTemp={userProfile.sincerityTemp} /> - {/* 랭킹 & 도서관 바로가기 (통합 페이지로 연결) */} -
- - - -
+ {/* 1:1 인사이트 버튼 제거됨 - 이제 홈 페이지 탭에서 접근 가능 */} {userProfile.studyApplied ? ( From af563a56426ec5e9e1dc2a980a4737b0da845bdf Mon Sep 17 00:00:00 2001 From: Hyeonjun0527 Date: Wed, 21 Jan 2026 13:54:28 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=EC=8A=A4=ED=8B=B0=ED=82=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(service)/home/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(service)/home/page.tsx b/src/app/(service)/home/page.tsx index dd28de4b..956b1618 100644 --- a/src/app/(service)/home/page.tsx +++ b/src/app/(service)/home/page.tsx @@ -32,7 +32,7 @@ export default async function Home() { -