From 5e03e48be5f197090a4b557e858db44eeb23f7ee Mon Sep 17 00:00:00 2001 From: caadiq Date: Wed, 21 Jan 2026 18:03:06 +0900 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20Phase=208=20-=20=EC=95=A8?= =?UTF-8?q?=EB=B2=94=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 앨범 페이지: - Album.jsx: PC/Mobile 통합 (useIsMobile 분기) - PC: 통계 + 4열 그리드 + 호버 오버레이 - Mobile: 2열 그리드 간소화 훅 추가: - useAlbums: 앨범 목록 조회 - useAlbumDetail: 앨범 상세 조회 - useAlbumGallery: 앨범 갤러리 조회 라우팅: - /album 라우트 추가 Co-Authored-By: Claude Opus 4.5 --- frontend-temp/src/App.jsx | 13 +- frontend-temp/src/hooks/index.js | 3 + frontend-temp/src/hooks/useAlbumData.js | 36 +++++ frontend-temp/src/pages/album/Album.jsx | 188 ++++++++++++++++++++++++ frontend-temp/src/pages/album/index.js | 4 + frontend-temp/src/pages/index.js | 1 + 6 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 frontend-temp/src/hooks/useAlbumData.js create mode 100644 frontend-temp/src/pages/album/Album.jsx create mode 100644 frontend-temp/src/pages/album/index.js diff --git a/frontend-temp/src/App.jsx b/frontend-temp/src/App.jsx index bf1e760..234310a 100644 --- a/frontend-temp/src/App.jsx +++ b/frontend-temp/src/App.jsx @@ -3,7 +3,7 @@ import { cn, getTodayKST, formatFullDate } from "@/utils"; import { useUIStore } from "@/stores"; import { useIsMobile, useCategories, useScheduleData } from "@/hooks"; import { ErrorBoundary, Loading, ToastContainer, ScheduleCard, Layout } from "@/components"; -import { Schedule } from "@/pages"; +import { Schedule, Album } from "@/pages"; /** * 홈 페이지 (임시) @@ -137,10 +137,9 @@ function Home() { /** * 프로미스나인 팬사이트 메인 앱 * - * Phase 7: 스케줄 페이지 마이그레이션 - * - Layout 컴포넌트 (PC/Mobile 통합) - * - Header, Footer, MobileNav 컴포넌트 - * - Schedule 페이지 (기본 구조) + * Phase 8: 앨범 페이지 마이그레이션 + * - Album 페이지 (PC/Mobile 통합) + * - useAlbums 훅 추가 */ function App() { return ( @@ -178,11 +177,13 @@ function App() { } /> + {/* 앨범 */} -
앨범 페이지 (준비 중)
+ + } /> diff --git a/frontend-temp/src/hooks/index.js b/frontend-temp/src/hooks/index.js index c0447fe..7bd4b1d 100644 --- a/frontend-temp/src/hooks/index.js +++ b/frontend-temp/src/hooks/index.js @@ -24,3 +24,6 @@ export { useCalendar } from './useCalendar'; // 인증 export { useAdminAuth, useRedirectIfAuthenticated } from './useAdminAuth'; + +// 앨범 데이터 +export { useAlbums, useAlbumDetail, useAlbumGallery } from './useAlbumData'; diff --git a/frontend-temp/src/hooks/useAlbumData.js b/frontend-temp/src/hooks/useAlbumData.js new file mode 100644 index 0000000..1ec0068 --- /dev/null +++ b/frontend-temp/src/hooks/useAlbumData.js @@ -0,0 +1,36 @@ +import { useQuery } from '@tanstack/react-query'; +import { albumsApi } from '@/api'; + +/** + * 앨범 목록 조회 훅 + */ +export function useAlbums() { + return useQuery({ + queryKey: ['albums'], + queryFn: albumsApi.getAlbums, + }); +} + +/** + * 앨범 상세 조회 훅 + * @param {string} title - 앨범 타이틀 또는 폴더명 + */ +export function useAlbumDetail(title) { + return useQuery({ + queryKey: ['album', title], + queryFn: () => albumsApi.getAlbumByTitle(title), + enabled: !!title, + }); +} + +/** + * 앨범 갤러리 조회 훅 + * @param {string} title - 앨범 타이틀 또는 폴더명 + */ +export function useAlbumGallery(title) { + return useQuery({ + queryKey: ['album-gallery', title], + queryFn: () => albumsApi.getAlbumGallery(title), + enabled: !!title, + }); +} diff --git a/frontend-temp/src/pages/album/Album.jsx b/frontend-temp/src/pages/album/Album.jsx new file mode 100644 index 0000000..ee8d8fa --- /dev/null +++ b/frontend-temp/src/pages/album/Album.jsx @@ -0,0 +1,188 @@ +import { useNavigate } from 'react-router-dom'; +import { motion } from 'framer-motion'; +import { Calendar, Music } from 'lucide-react'; +import { useIsMobile } from '@/hooks'; +import { useAlbums } from '@/hooks'; +import { Loading } from '@/components'; +import { formatDate } from '@/utils'; + +/** + * 앨범 목록 페이지 (PC/Mobile 통합) + */ +function Album() { + const navigate = useNavigate(); + const isMobile = useIsMobile(); + + // useQuery로 앨범 데이터 로드 + const { data: albums = [], isLoading } = useAlbums(); + + // 타이틀곡 찾기 + const getTitleTrack = (tracks) => { + if (!tracks || tracks.length === 0) return ''; + const titleTrack = tracks.find((t) => t.is_title_track); + return titleTrack ? titleTrack.title : tracks[0].title; + }; + + // 앨범 타입 (short 우선) + const getAlbumType = (album) => album.album_type_short || album.album_type; + + // 앨범 통계 + const albumStats = { + 정규: albums.filter((a) => getAlbumType(a) === '정규').length, + 미니: albums.filter((a) => getAlbumType(a) === '미니').length, + 싱글: albums.filter((a) => getAlbumType(a) === '싱글').length, + 총: albums.length, + }; + + // 앨범 클릭 핸들러 + const handleAlbumClick = (album) => { + const path = isMobile ? album.folder_name : encodeURIComponent(album.title); + navigate(`/album/${path}`); + }; + + if (isLoading) { + return ( +
+ +
+ ); + } + + // 모바일 레이아웃 + if (isMobile) { + return ( +
+
+ {albums.map((album, index) => ( + handleAlbumClick(album)} + className="bg-white rounded-2xl overflow-hidden shadow-md cursor-pointer" + > +
+ {album.cover_thumb_url && ( + {album.title} + )} +
+
+

{album.title}

+

+ {getAlbumType(album)} · {album.release_date?.slice(0, 4)} +

+
+
+ ))} +
+
+ ); + } + + // PC 레이아웃 + return ( +
+
+ {/* 헤더 */} +
+ + 앨범 + + + 프로미스나인의 음악을 만나보세요 + +
+ + {/* 통계 */} + +
+

{albumStats.정규}

+

정규 앨범

+
+
+

{albumStats.미니}

+

미니 앨범

+
+
+

{albumStats.싱글}

+

싱글 앨범

+
+
+

{albumStats.총}

+

총 앨범

+
+
+ + {/* 앨범 그리드 */} +
+ {albums.map((album, index) => ( + handleAlbumClick(album)} + > + {/* 앨범 커버 */} +
+ {album.title} + + {/* 호버 오버레이 */} +
+
+ +

{album.tracks?.length || 0}곡 수록

+
+
+
+ + {/* 앨범 정보 */} +
+
+

{album.title}

+ + {getAlbumType(album)} + +
+

+ {getTitleTrack(album.tracks)} +

+
+ + {formatDate(album.release_date, 'YYYY.MM.DD')} +
+
+
+ ))} +
+
+
+ ); +} + +export default Album; diff --git a/frontend-temp/src/pages/album/index.js b/frontend-temp/src/pages/album/index.js new file mode 100644 index 0000000..64aae39 --- /dev/null +++ b/frontend-temp/src/pages/album/index.js @@ -0,0 +1,4 @@ +/** + * 앨범 페이지 export + */ +export { default as Album } from './Album'; diff --git a/frontend-temp/src/pages/index.js b/frontend-temp/src/pages/index.js index 3b7c75b..2a3da66 100644 --- a/frontend-temp/src/pages/index.js +++ b/frontend-temp/src/pages/index.js @@ -2,3 +2,4 @@ * 페이지 export */ export * from './schedule'; +export * from './album';