diff --git a/frontend/src/pages/mobile/public/Album.jsx b/frontend/src/pages/mobile/public/Album.jsx index 22a4d2d..1fca0a7 100644 --- a/frontend/src/pages/mobile/public/Album.jsx +++ b/frontend/src/pages/mobile/public/Album.jsx @@ -1,22 +1,18 @@ import { motion } from 'framer-motion'; -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { getAlbums } from '../../../api/public/albums'; // 모바일 앨범 목록 페이지 function MobileAlbum() { const navigate = useNavigate(); - const [albums, setAlbums] = useState([]); - const [loading, setLoading] = useState(true); - useEffect(() => { - getAlbums() - .then(data => { - setAlbums(data); - setLoading(false); - }) - .catch(console.error); - }, []); + // useQuery로 앨범 데이터 로드 + const { data: albums = [], isLoading: loading } = useQuery({ + queryKey: ['albums'], + queryFn: getAlbums, + }); + if (loading) { return ( diff --git a/frontend/src/pages/mobile/public/Home.jsx b/frontend/src/pages/mobile/public/Home.jsx index 89f43df..8689b4e 100644 --- a/frontend/src/pages/mobile/public/Home.jsx +++ b/frontend/src/pages/mobile/public/Home.jsx @@ -1,6 +1,6 @@ import { motion } from 'framer-motion'; import { ChevronRight, Clock, Tag } from 'lucide-react'; -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { getTodayKST } from '../../../utils/date'; import { getMembers } from '../../../api/public/members'; @@ -10,27 +10,27 @@ import { getUpcomingSchedules } from '../../../api/public/schedules'; // 모바일 홈 페이지 function MobileHome() { const navigate = useNavigate(); - const [members, setMembers] = useState([]); - const [albums, setAlbums] = useState([]); - const [schedules, setSchedules] = useState([]); - // 데이터 로드 - useEffect(() => { - // 멤버 로드 - getMembers() - .then(data => setMembers(data.filter(m => !m.is_former))) - .catch(console.error); + // useQuery로 멤버 데이터 로드 (활동 중인 멤버만) + const { data: members = [] } = useQuery({ + queryKey: ['members'], + queryFn: getMembers, + select: (data) => data.filter(m => !m.is_former), + }); - // 앨범 로드 (최신 2개) - getAlbums() - .then(data => setAlbums(data.slice(0, 2))) - .catch(console.error); + // useQuery로 앨범 로드 (최신 2개) + const { data: albums = [] } = useQuery({ + queryKey: ['albums'], + queryFn: getAlbums, + select: (data) => data.slice(0, 2), + }); + + // useQuery로 다가오는 일정 로드 + const { data: schedules = [] } = useQuery({ + queryKey: ['upcomingSchedules', 3], + queryFn: () => getUpcomingSchedules(3), + }); - // 다가오는 일정 로드 - getUpcomingSchedules(3) - .then(data => setSchedules(data)) - .catch(console.error); - }, []); return (
diff --git a/frontend/src/pages/mobile/public/Members.jsx b/frontend/src/pages/mobile/public/Members.jsx index e63ea31..be9db69 100644 --- a/frontend/src/pages/mobile/public/Members.jsx +++ b/frontend/src/pages/mobile/public/Members.jsx @@ -1,22 +1,23 @@ import { motion, AnimatePresence } from 'framer-motion'; -import { useState, useEffect } from 'react'; +import { useState, useMemo } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { Instagram, Calendar, X } from 'lucide-react'; import { getMembers } from '../../../api/public/members'; // 모바일 멤버 페이지 function MobileMembers() { - const [members, setMembers] = useState([]); - const [formerMembers, setFormerMembers] = useState([]); const [selectedMember, setSelectedMember] = useState(null); - useEffect(() => { - getMembers() - .then(data => { - setMembers(data.filter(m => !m.is_former)); - setFormerMembers(data.filter(m => m.is_former)); - }) - .catch(console.error); - }, []); + // useQuery로 멤버 데이터 로드 + const { data: allMembers = [] } = useQuery({ + queryKey: ['members'], + queryFn: getMembers, + }); + + // useMemo로 현재/전 멤버 분리 + const members = useMemo(() => allMembers.filter(m => !m.is_former), [allMembers]); + const formerMembers = useMemo(() => allMembers.filter(m => m.is_former), [allMembers]); + // 나이 계산 const calculateAge = (birthDate) => { diff --git a/frontend/src/pages/pc/public/Album.jsx b/frontend/src/pages/pc/public/Album.jsx index e2ac260..b63946d 100644 --- a/frontend/src/pages/pc/public/Album.jsx +++ b/frontend/src/pages/pc/public/Album.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; import { Calendar, Music } from 'lucide-react'; @@ -7,20 +7,13 @@ import { formatDate } from '../../../utils/date'; function Album() { const navigate = useNavigate(); - const [albums, setAlbums] = useState([]); - const [loading, setLoading] = useState(true); + + // useQuery로 앨범 데이터 로드 + const { data: albums = [], isLoading: loading } = useQuery({ + queryKey: ['albums'], + queryFn: getAlbums, + }); - useEffect(() => { - getAlbums() - .then(data => { - setAlbums(data); - setLoading(false); - }) - .catch(error => { - console.error('앨범 데이터 로드 오류:', error); - setLoading(false); - }); - }, []); // 타이틀곡 찾기 const getTitleTrack = (tracks) => { diff --git a/frontend/src/pages/pc/public/Home.jsx b/frontend/src/pages/pc/public/Home.jsx index c40a54b..d5b3e95 100644 --- a/frontend/src/pages/pc/public/Home.jsx +++ b/frontend/src/pages/pc/public/Home.jsx @@ -1,260 +1,304 @@ -import { useState, useEffect } from 'react'; -import { motion } from 'framer-motion'; -import { Link } from 'react-router-dom'; -import { Calendar, ArrowRight, Clock, Link2, Tag } from 'lucide-react'; -import { getTodayKST } from '../../../utils/date'; -import { getMembers } from '../../../api/public/members'; -import { getUpcomingSchedules } from '../../../api/public/schedules'; +import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { motion } from "framer-motion"; +import { Link } from "react-router-dom"; +import { Calendar, ArrowRight, Clock, Link2, Tag } from "lucide-react"; +import { getTodayKST } from "../../../utils/date"; +import { getMembers } from "../../../api/public/members"; +import { getUpcomingSchedules } from "../../../api/public/schedules"; function Home() { - const [members, setMembers] = useState([]); - const [upcomingSchedules, setUpcomingSchedules] = useState([]); + // useQuery로 멤버 데이터 로드 + const { data: members = [] } = useQuery({ + queryKey: ["members"], + queryFn: getMembers, + }); - useEffect(() => { - // 멤버 데이터 로드 - getMembers() - .then(data => setMembers(data)) - .catch(error => console.error('멤버 데이터 로드 오류:', error)); - - // 다가오는 일정 로드 (오늘 이후 3개) - getUpcomingSchedules(3) - .then(data => setUpcomingSchedules(data)) - .catch(error => console.error('일정 데이터 로드 오류:', error)); - }, []); + // useQuery로 다가오는 일정 로드 (오늘 이후 3개) + const { data: upcomingSchedules = [] } = useQuery({ + queryKey: ["upcomingSchedules", 3], + queryFn: () => getUpcomingSchedules(3), + }); - return ( -
- {/* 히어로 섹션 */} -
-
-
- -

fromis_9

-

프로미스나인

-

- 인사드리겠습니다. 둘, 셋!
- 이제는 약속해 소중히 간직해,
- 당신의 아이돌로 성장하겠습니다! -

- - 멤버 보기 - - -
-
- - {/* 장식 */} -
-
-
-
-
- - {/* 그룹 통계 섹션 */} -
-
- - {[ - { value: "2018.01.24", label: "데뷔일" }, - { value: `D+${(Math.floor((new Date() - new Date('2018-01-24')) / (1000 * 60 * 60 * 24)) + 1).toLocaleString()}`, label: "D+Day" }, - { value: "5", label: "멤버 수" }, - { value: "flover", label: "팬덤명" } - ].map((stat, index) => ( - -

{stat.value}

-

{stat.label}

-
- ))} -
-
-
- - {/* 멤버 미리보기 */} -
-
-
-

멤버

- - 전체보기 - -
-
- {members.filter(m => !m.is_former).map((member, index) => ( - - {/* 이미지 컨테이너 */} -
- {member.name} -
- - {/* 그라데이션 오버레이 */} -
- - {/* 멤버 정보 */} -
-

{member.name}

-
- - ))} -
-
-
- - {/* 일정 미리보기 */} -
-
-
-

다가오는 일정

- - 전체보기 - -
- {upcomingSchedules.length === 0 ? ( -
- -

예정된 일정이 없습니다

-
- ) : ( - - {upcomingSchedules.map((schedule) => { - const scheduleDate = new Date(schedule.date); - const today = new Date(); - const currentYear = today.getFullYear(); - const currentMonth = today.getMonth(); - - const scheduleYear = scheduleDate.getFullYear(); - const scheduleMonth = scheduleDate.getMonth(); - const isCurrentYear = scheduleYear === currentYear; - const isCurrentMonth = isCurrentYear && scheduleMonth === currentMonth; - - const day = scheduleDate.getDate(); - const weekdays = ['일', '월', '화', '수', '목', '금', '토']; - const weekday = weekdays[scheduleDate.getDay()]; - - // 멤버 처리 - const memberList = schedule.member_names ? schedule.member_names.split(',') : []; - const displayMembers = memberList.length >= 5 ? ['프로미스나인'] : memberList; - - return ( - - {/* 날짜 영역 - primary 색상 고정 */} -
- {/* 현재 년도가 아니면 년.월 표시 */} - {!isCurrentYear && ( - - {scheduleYear}.{scheduleMonth + 1} - - )} - {/* 현재 달이 아니면 월 표시 (현재 년도일 때) */} - {isCurrentYear && !isCurrentMonth && ( - - {scheduleMonth + 1}월 - - )} - {day} - {weekday} -
- - {/* 내용 영역 */} -
-

{schedule.title}

- -
- {schedule.time && ( -
- - {schedule.time.slice(0, 5)} -
- )} - {schedule.category_name && ( -
- - {schedule.category_name} -
- )} - {schedule.source_name && ( -
- - {schedule.source_name} -
- )} -
- - {/* 멤버 태그 */} - {displayMembers.length > 0 && ( -
- {displayMembers.map((name, i) => ( - - {name.trim()} - - ))} -
- )} -
-
- ); - })} -
- )} - - -
-
+ return ( +
+ {/* 히어로 섹션 */} +
+
+
+ +

fromis_9

+

프로미스나인

+

+ 인사드리겠습니다. 둘, 셋! +
+ 이제는 약속해 소중히 간직해, +
+ 당신의 아이돌로 성장하겠습니다! +

+ + 멤버 보기 + + +
- ); + + {/* 장식 */} +
+
+
+
+
+ + {/* 그룹 통계 섹션 */} +
+
+ + {[ + { value: "2018.01.24", label: "데뷔일" }, + { + value: `D+${( + Math.floor( + (new Date() - new Date("2018-01-24")) / + (1000 * 60 * 60 * 24) + ) + 1 + ).toLocaleString()}`, + label: "D+Day", + }, + { value: "5", label: "멤버 수" }, + { value: "flover", label: "팬덤명" }, + ].map((stat, index) => ( + +

{stat.value}

+

{stat.label}

+
+ ))} +
+
+
+ + {/* 멤버 미리보기 */} +
+
+
+

멤버

+ + 전체보기 + +
+
+ {members + .filter((m) => !m.is_former) + .map((member, index) => ( + + {/* 이미지 컨테이너 */} +
+ {member.name} +
+ + {/* 그라데이션 오버레이 */} +
+ + {/* 멤버 정보 */} +
+

+ {member.name} +

+
+ + ))} +
+
+
+ + {/* 일정 미리보기 */} +
+
+
+

다가오는 일정

+ + 전체보기 + +
+ {upcomingSchedules.length === 0 ? ( +
+ +

예정된 일정이 없습니다

+
+ ) : ( + + {upcomingSchedules.map((schedule) => { + const scheduleDate = new Date(schedule.date); + const today = new Date(); + const currentYear = today.getFullYear(); + const currentMonth = today.getMonth(); + + const scheduleYear = scheduleDate.getFullYear(); + const scheduleMonth = scheduleDate.getMonth(); + const isCurrentYear = scheduleYear === currentYear; + const isCurrentMonth = + isCurrentYear && scheduleMonth === currentMonth; + + const day = scheduleDate.getDate(); + const weekdays = ["일", "월", "화", "수", "목", "금", "토"]; + const weekday = weekdays[scheduleDate.getDay()]; + + // 멤버 처리 + const memberList = schedule.member_names + ? schedule.member_names.split(",") + : []; + const displayMembers = + memberList.length >= 5 ? ["프로미스나인"] : memberList; + + return ( + + {/* 날짜 영역 - primary 색상 고정 */} +
+ {/* 현재 년도가 아니면 년.월 표시 */} + {!isCurrentYear && ( + + {scheduleYear}.{scheduleMonth + 1} + + )} + {/* 현재 달이 아니면 월 표시 (현재 년도일 때) */} + {isCurrentYear && !isCurrentMonth && ( + + {scheduleMonth + 1}월 + + )} + {day} + + {weekday} + +
+ + {/* 내용 영역 */} +
+

+ {schedule.title} +

+ +
+ {schedule.time && ( +
+ + {schedule.time.slice(0, 5)} +
+ )} + {schedule.category_name && ( +
+ + {schedule.category_name} +
+ )} + {schedule.source_name && ( +
+ + {schedule.source_name} +
+ )} +
+ + {/* 멤버 태그 */} + {displayMembers.length > 0 && ( +
+ {displayMembers.map((name, i) => ( + + {name.trim()} + + ))} +
+ )} +
+
+ ); + })} +
+ )} +
+
+
+ ); } export default Home; - diff --git a/frontend/src/pages/pc/public/Members.jsx b/frontend/src/pages/pc/public/Members.jsx index e529ab3..a641b35 100644 --- a/frontend/src/pages/pc/public/Members.jsx +++ b/frontend/src/pages/pc/public/Members.jsx @@ -1,24 +1,16 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { motion } from 'framer-motion'; import { Instagram, Calendar } from 'lucide-react'; import { getMembers } from '../../../api/public/members'; import { formatDate } from '../../../utils/date'; function Members() { - const [members, setMembers] = useState([]); - const [loading, setLoading] = useState(true); + // useQuery로 멤버 데이터 로드 + const { data: members = [], isLoading: loading } = useQuery({ + queryKey: ['members'], + queryFn: getMembers, + }); - useEffect(() => { - getMembers() - .then(data => { - setMembers(data); - setLoading(false); - }) - .catch(error => { - console.error('데이터 로드 오류:', error); - setLoading(false); - }); - }, []); if (loading) { return (