Skip to content
Merged
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
20 changes: 9 additions & 11 deletions src/pages/myPage/CheckedIdolCard.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { useState, useEffect } from 'react';
import checkIcon from '@/assets/images/check.png';
import PrimaryButton from '@/components/PrimaryButton';
import xButton from '@/assets/icons/xButton.svg';

const CheckedIdolCard = ({
children,
idol,
isSelectable = true,
isSelected = false,
isFavorte = false,
onRemove,
sizeClass = 'w-[98px] h-[98px] tablet:w-[128px] tablet:h-[128px]',
}) => {
const defaultImage = 'https://link24.kr/9iFIhh0';
const storageKey = 'favoriteIdols';
Expand Down Expand Up @@ -38,16 +36,16 @@ const CheckedIdolCard = ({
};

return (
<div className="p-1 flex flex-col items-center">
<div className="p-1 flex flex-col items-center relative ">
<div
className={`relative w-[98px] h-[98px] md:w-[128px] md:h-[128px] p-[2px]
flex items-center justify-center rounded-full
${isSelectable ? 'cursor-pointer' : 'cursor-default'} transition-all`}
className={`relative ${sizeClass} p-[2px] flex items-center justify-center rounded-full
${isSelectable ? 'cursor-pointer' : 'cursor-default'} transition-all`}
onClick={isSelectable ? toggleFavorite : undefined}
>
<div className="absolute inset-0 rounded-full border-[1.3px] border-coralRed border-opacity-100 z-10"></div>
{children}
<div className="absolute inset-0 rounded-full border-[1.3px] border-coralRed z-10"></div>

<div className="absolute inset-0 m-1.5 over rounded-full overflow-hidden">
<div className="absolute inset-0 m-1.5 rounded-full overflow-hidden">
<img
src={idol.profilePicture || defaultImage}
alt={idol.name}
Expand All @@ -68,7 +66,7 @@ const CheckedIdolCard = ({
</div>

<div className="mt-1 text-center">
<p className="text-white text-sm font-bold">{idol.name}</p>
<p className="text-white text-mobile font-bold">{idol.name}</p>
<p className="text-white/70 text-xs">{idol.group || '그룹 없음'}</p>
</div>
</div>
Expand Down
174 changes: 85 additions & 89 deletions src/pages/myPage/MyPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import nextIcon from '@/assets/icons/nextIcon.svg';
import prevIcon from '@/assets/icons/prevIcon.svg';
import { fetchIdols } from '@/apis/myPageApi.js';
import PrimaryButton from '@/components/PrimaryButton';
import xButton from '@/assets/icons/xButton.svg';

const storageKey = 'favoriteIdols';

Expand All @@ -14,19 +15,28 @@ const MyPage = () => {
const [favoriteIdols, setFavoriteIdols] = useState([]);
const [currentPage, setCurrentPage] = useState(0);
const [itemsPerPage, setItemsPerPage] = useState(16);

const favoriteIdSet = new Set(favoriteIdols.map(Number)); // 숫자로 변환한 Set 생성
const favoriteIdolsArr = idols.filter((idol) => favoriteIdSet.has(idol.id));

const handleAddToFavorites = () => {
if (selectedIdols.length === 0) return;

setFavoriteIdols((prev) => {
const updatedFavorites = [...new Set([...prev, ...selectedIdols])];
localStorage.setItem(storageKey, updatedFavorites.join(',')); // localStorage 업데이트
return updatedFavorites;
});

setSelectedIdols([]); // 선택된 아이돌 초기화
};

useEffect(() => {
const updateItemsPerPage = () => {
const width = window.innerWidth;
if (width >= 1200) {
setItemsPerPage(16);
} else if (width >= 768) {
setItemsPerPage(8);
} else {
setItemsPerPage(6);
}
if (width >= 1200) setItemsPerPage(16);
else if (width >= 768) setItemsPerPage(8);
else setItemsPerPage(6);
};

updateItemsPerPage();
Expand All @@ -36,7 +46,7 @@ const MyPage = () => {

useEffect(() => {
const loadIdols = async () => {
const data = await fetchIdols(30);
const data = await fetchIdols(32);
setIdols(data);
};
loadIdols();
Expand All @@ -47,36 +57,26 @@ const MyPage = () => {
if (storedFavorites) {
setFavoriteIdols(storedFavorites.split(','));
}
}, []);
}, []); // `favoriteIdols` 변경될 때마다 실행

const handleToggle = (idolId) => {
setSelectedIdols((prev) => {
const index = prev.indexOf(idolId);
if (index !== -1) {
// 이미 선택된 경우, 해당 인덱스의 항목만 제거
return [...prev.slice(0, index), ...prev.slice(index + 1)];
} else {
// 선택되지 않은 경우, 배열에 추가
return [...prev, idolId];
}
});
setSelectedIdols((prev) =>
prev.includes(idolId)
? prev.filter((id) => id !== idolId)
: [...prev, idolId]
);
};
const handleAddToFavorites = () => {
if (selectedIdols.length === 0) return;
else {
setFavoriteIdols((prev) => {
const updatedFavorites = [...new Set([...prev, ...selectedIdols])];
localStorage.setItem(storageKey, updatedFavorites.join(','));
return updatedFavorites;
});
}
setSelectedIdols([]);

const handleRemoveFavorite = (idolId) => {
setFavoriteIdols((prev) => {
const updatedFavorites = prev.filter((id) => id !== idolId.toString());
localStorage.setItem(storageKey, updatedFavorites.join(','));
return updatedFavorites;
});
};

const prevPage = () => {
if (currentPage > 0) {
setCurrentPage((prev) => prev - 1);
}
if (currentPage > 0) setCurrentPage((prev) => prev - 1);
};

const nextPage = () => {
Expand All @@ -86,67 +86,78 @@ const MyPage = () => {
};

return (

<div className="w-full min-h-screen bg-[#02000E] flex flex-col items-center font-pretendard">
<div className="w-full min-h-screen bg-midnightBlack flex flex-col items-center font-pretendard">
<Header />

{/* 관심있는 아이돌 섹션 */}
<div className="w-full max-w-[1200px] flex flex-col items-center py-6 sm:py-10">
<h1 className="text-white text-[16px] tablet:text-[20px] pc:text-[24px] font-bold self-start">
<div className="w-full max-w-[1200px] flex flex-col items-center py-6 mobile:py-10">
<h1 className="text-white text-[16px] tablet:text-[20px] pc:text-[24px] font-pretendard font-bold self-start">
내가 관심있는 아이돌
</h1>
{/*스크롤시 배경 전체유지 */}
<style>
{`
html, body {
background-color: #02000E; /* 브라우저 전체 배경 */
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow-x: hidden; /* 가로 스크롤 방지 */
}
`}
</style>
<div className="w-full overflow-x-auto scrollbar-thin scrollbar-thumb-steelGray">
<div className="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-8 gap-3 mt-4 mx-auto min-h-[150px]">
{favoriteIdolsArr.map((idol) => {
return (

<div className="w-full overflow-x-auto whitespace-nowrap scrollbar-hide">
<div className=" flex gap-5 mt-4 mx-auto min-h-[150px]">
{favoriteIdolsArr.map((idol) => (
<div key={idol.id} className="relative">
<CheckedIdolCard
key={idol.id}
className="relative"
idol={idol}
isSelectable={false}
/>
);
})}
sizeClass="w-[100px] h-[100px]"
>
{/* 닫기 버튼 */}
{/* X 버튼 (항상 테두리 상단에 고정) */}
<button
onClick={() => handleRemoveFavorite(idol.id)}
className="absolute top-0 right-0
flex items-center justify-center bg-transparent
transition-opacity z-30 "
>
<img src={xButton} alt="Remove" className="w-full h-full" />
</button>
</CheckedIdolCard>
</div>
))}
</div>
</div>

{/* 회색 구분선 */}
{/* 회색 구분선 */}
<div className="relative w-full max-w-[1200px] mt-4 border-t border-gray-900" />

{/* 아이돌 추가하기 섹션 */}
<h2 className="text-white text-[16px] tablet:text-[20px] pc:text-[24px] font-bold self-start mt-6">
<h2 className="text-white text-[16px] tablet:text-[20px] pc:text-[24px] font-pretendard font-bold self-start mt-6">
관심 있는 아이돌을 추가해보세요.
</h2>

{/* 버튼이 그리드 크기에 따라 자동으로 좌우 맞춤 */}
{/* 버튼이 그리드 크기에 따라 자동으로 좌우 맞춤 */}
<div className="relative w-full max-w-[1200px] mt-[20px]">
{/* 이전 버튼 (반응형 위치 조정) */}
{/* 이전 버튼 */}

<button
onClick={prevPage}
disabled={currentPage === 0}
className="absolute left-[1%] md:left-[-6%] lg:left-[-4%] top-1/2 transform -translate-y-1/2
className="absolute left-[1%] tablet:left-[-6%] pc:left-[-4%] top-1/2 transform -translate-y-1/2
w-[29px] h-[135px] rounded-[4px]
bg-[rgba(27,27,27,0.8)]
hover:bg-[rgba(27,27,27,1)] transition-all
flex items-center justify-center"
>
<img src={prevIcon} alt="Previous" className="w-4 h-4" />
</button>

{/* 아이돌 리스트 */}
<div className="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-8 gap-3 mt-4 mx-auto min-h-[300px]">
{/* 이후 버튼 */}
<button
onClick={nextPage}
disabled={(currentPage + 1) * itemsPerPage >= idols.length}
className="absolute right-[1%] tablet:right-[-6%] pc:right-[-4%] top-1/2 transform -translate-y-1/2
w-[29px] h-[135px] rounded-[4px]
bg-[rgba(27,27,27,0.8)]
hover:bg-[rgba(27,27,27,1)] transition-all
flex items-center justify-center"
>
<img src={nextIcon} alt="Next" className="w-4 h-4" />
</button>
{/* 아이돌 리스트 */}
<div className="grid grid-cols-3 tablet:grid-cols-4 pc:grid-cols-8 gap-3 mt-4 mx-auto min-h-[300px]">
{idols
.slice(
currentPage * itemsPerPage,
Expand All @@ -162,32 +173,17 @@ const MyPage = () => {
/>
))}
</div>

{/* 다음 버튼 (반응형 위치 조정) */}
<button
onClick={nextPage}
disabled={(currentPage + 1) * itemsPerPage >= idols.length}
className="absolute right-[1%] md:right-[-6%] lg:right-[-4%] top-1/2 transform -translate-y-1/2
w-[29px] h-[135px] rounded-[4px]
bg-[rgba(27,27,27,0.8)]
hover:bg-[rgba(27,27,27,1)] transition-all
flex items-center justify-center"
>
<img src={nextIcon} alt="Next" className="w-4 h-4" />
</button>
</div>
</div>

{/* 추가하기 버튼 중앙 정렬 */}
<div className="flex justify-center w-full">
<PrimaryButton
onClickFunc={handleAddToFavorites}
className={
'w-[255px] h-[48px] mt-10 text-white rounded-full font-pretendard font-bold text-[16px] hover:opacity-70 transition-all'
}
>
+ 추가하기
</PrimaryButton>
</div>
{/* 추가하기 버튼 */}
<div className="flex justify-center w-full">
<PrimaryButton
onClickFunc={handleAddToFavorites}
className="w-[255px] h-[48px] mt-10 text-white rounded-full font-pretendard font-bold text-[16px]"
>
+ 추가하기
</PrimaryButton>
</div>
</div>
);
Expand Down