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
10 changes: 10 additions & 0 deletions src/apis/idolListApi.js → src/apis/monthlyChartApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,13 @@ export async function getLists(gender, cursor = 0, pageSize) {
throw error;
}
}

export async function postVotes() {
try {
const res = await instance.post('/votes');
return res.data;
} catch (error) {
console.error(error);
throw error;
}
}
3 changes: 3 additions & 0 deletions src/assets/icons/exitArrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions src/components/Modal.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import closeButton from '@/assets/icons/closeButton.svg';
import leftTopGradient from '@/assets/images/leftTopGradient.png';
import exitArrow from '@/assets/icons/exitArrow.svg';
import { useEffect } from 'react';

function Modal({ title, onClose, children }) {
Expand All @@ -9,6 +11,34 @@ function Modal({ title, onClose, children }) {
};
}, []);

if (title.includes('아이돌') && window.innerWidth <= 375) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희 tailwind.config.js 파일 확인해보시면

screens: {
        pc: '1200px',
        tablet: '768px',
        mobile: '375px',
      },

모바일 화면 breakpoint가 375라 375px 이상이 모바일 화면인 것으로 알고 있습니다. 그래서 innerWidth가 768px 미만일 때 모바일 버전 투표 모달창을 보여주도록 조건을 바꿔줘야 할 것 같습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 지금은 화면이 375px 이하일 때 '차트 투표하기를 눌렀을 경우에만 제대로 모바일 버전 모달창이 나오는 것 같습니다.

  • 375px 이하의 화면에서 차트 투표하기를 눌렀을 때
    image

  • 위 상태에서 화면 사이즈가 375px을 초과했을 때
    image
    이렇게 화면 크기가 375px을 초과했는데도 여전히 모바일 버전 모달창으로 보입니다!

  • 375px을 초과한 사이즈의 화면에서 차트 투표하기를 눌렀을 때
    image

  • 위 상태에서 화면 사이즈가 375px 이하가 되었을 때
    image
    이렇게 화면 크기가 375px 이하가 되니 모바일 버전 모달창이 되는 것이 아닌, pc와 tablet에서 쓰이는 모달창이 계속 쓰여서 모달창이 많이 깨져있는 것을 확인했습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그래서 여기서도 반응형을 사용하는 건 어떨까 싶습니다

const [isMobile, setIsMobile] = useState(false);

...

useEffect(() => {
    const handleResize = () => {
      setIsMobile(window.innerWidth < 768);
    };
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

return (
<div className="fixed top-0 left-0 size-full bg-midnightBlack">
<img
src={leftTopGradient}
alt="leftTopGradient"
className="absolute w-[200px] h-[272px] opacity-70 z-10 pointer-events-none"
/>
<div className="fixed top-2 left-0 w-full h-screen font-pretendard mx-[24px]">
<div className="w-full h-[44px] flex justify-start items-center">
<img
src={exitArrow}
alt="exitArrow"
className="w-[24px] cursor-pointer"
onClick={onClose}
/>
{title && (
<div className="fixed top-[22px] left-1/2 -translate-x-1/2 justify-center items-center leading-[16.71px] text-[14px] font-medium text-softWhite mr-[14px]">
{title}
</div>
)}
</div>
{children}
</div>
</div>
);
}

return (
<div className="fixed top-0 left-0 w-[100%] h-[100%] flex justify-center items-center bg-black/80 font-pretendard">
<div className="relative bg-deepCharcoal p-[20px] rounded-[8px] py-[24px] px-[16px]">
Expand Down
26 changes: 26 additions & 0 deletions src/components/modalContent/MonthlyChartVoteList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import MonthlyChartItem from '@/pages/listPage/monthlyChart/MonthlyChartItem';

const MonthlyChartVoteList = ({ idols, selectedIdol, setSelectedIdol }) => {
return (
<div className="flex flex-col mt-[24px] mb-[40px]">
{idols.map((idol, idx) => (
<div key={idol.id} onClick={() => setSelectedIdol(idol.id)}>
<MonthlyChartItem idol={idol} rank={idx + 1} layout="vote">
<div className="relative flex items-center justify-center">
<div
className={`w-[16px] h-[16px] rounded-full border-[2px] bg-gray-100 border-gray-300 ${selectedIdol === idol.id ? 'border-coralRed' : ''} flex items-center justify-center`}
>
<div
className={`absolute w-2 h-2 rounded-full bg-coralRed transition-transform ${selectedIdol === idol.id ? 'scale-100' : 'scale-0'}`}
/>
</div>
</div>
</MonthlyChartItem>
<div className="w-full h-[1px] bg-white bg-opacity-10 my-[4px]"></div>
</div>
))}
</div>
);
};

export default MonthlyChartVoteList;
67 changes: 67 additions & 0 deletions src/components/modalContent/MonthlyChartVoteModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useState, useEffect } from 'react';
import MonthlyChartVoteList from '@/components/modalContent/MonthlyChartVoteList';
import { getLists } from '@/apis/monthlyChartApi';
import PrimaryButton from '@/components/PrimaryButton';

const MonthlyChartVoteModal = ({ gender }) => {
const [cursor, setCursor] = useState(0);
const [idolData, setIdolData] = useState([]);
const [loading, setLoading] = useState(false);
const [selectedIdol, setSelectedIdol] = useState(0);

const loadIdolData = async () => {
setLoading(true);
try {
const response = await getLists(gender, cursor, 10);
if (cursor !== 0) {
setIdolData((prev) => [...prev, ...response.idols]);
} else {
setIdolData(response.idols);
}
setCursor(response.nextCursor);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};

const loadMoreData = () => {
if (cursor === null) {
alert('불러올 데이터가 없습니다.');
} else {
loadIdolData();
}
};

useEffect(() => {
setIdolData([]);
setCursor(0);
loadIdolData();
}, [gender]);

return (
<div className="w-[calc(100%-48px)] h-[693px] tablet:w-[525px] tablet:h-[693px] pc:w-[525px] pc:h-[693px] overflow-y-auto">
{loading ? (
<div className="text-center text-white">로딩 중입니다...</div>
) : (
<MonthlyChartVoteList
idols={idolData}
selectedIdol={selectedIdol}
setSelectedIdol={setSelectedIdol}
/>
)}
<div className="fixed bottom-0 w-[calc(100%-48px)] h-[106px] text-white leading-[26px] bg-midnightBlack/80 tablet:w-[525px] pc:w-[525px] tablet:bg-transparent pc:bg-transparent">
<PrimaryButton className="w-full h-[42px] font-bold text-[14px] font-pretendard">
투표하기
</PrimaryButton>
<p className="font-medium text-[12px] text-center">
투표하는 데<span className=" text-coralRed"> 1000 크레딧</span>이
소모됩니다.
</p>
</div>
</div>
);
};

export default MonthlyChartVoteModal;
12 changes: 11 additions & 1 deletion src/pages/listPage/ListPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import DonationModalContent from '@/components/modalContent/DonationModalContent
import leftTopGradient from '@/assets/images/leftTopGradient.png';
import DonationSuccess from '@/components/modalContent/DonationSuccess';
import MonthlyChartSection from '@/pages/listPage/monthlyChart/MonthlyChartSection';
import MonthlyChartVoteModal from '../../components/modalContent/MonthlyChartVoteModal';

function ListPage() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalStep, setModalStep] = useState(null);
const [credits, setCredits] = useState(getCredits());
const [selectedAmount, setSelectedAmount] = useState(null);
const [selectedItem, setSelectedItem] = useState(null);
const [gender, setGender] = useState('female');

useEffect(() => {
setCredits(getCredits());
Expand Down Expand Up @@ -53,6 +55,7 @@ function ListPage() {
creditNotEnough: '',
donation: '후원하기',
donationSuccess: '',
vote: `이달의 ${gender === 'female' ? '여자' : '남자'} 아이돌`,
}[modalStep];

return (
Expand All @@ -69,7 +72,13 @@ function ListPage() {
credits={credits}
/>
<DonationsList onDonationClick={(item) => openModal('donation', item)} />
<MonthlyChartSection />
<MonthlyChartSection
onClickVote={() => {
openModal('vote');
}}
gender={gender}
setGender={setGender}
/>

{isModalOpen && (
<Modal title={modalTitle} onClose={closeModal}>
Expand Down Expand Up @@ -102,6 +111,7 @@ function ListPage() {
{modalStep === 'donationSuccess' && (
<DonationSuccess onConfirm={closeModal} />
)}
{modalStep === 'vote' && <MonthlyChartVoteModal gender={gender} />}
</Modal>
)}
</div>
Expand Down
66 changes: 48 additions & 18 deletions src/pages/listPage/monthlyChart/MonthlyChartItem.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,56 @@
import IdolCard from '@/components/IdolCard';

const MonthlyChartItem = ({ idol }) => {
const { profilePicture, name, rank, group, totalVotes } = idol;
const MonthlyChartItem = ({ idol, rank, layout = 'default', children }) => {
const { profilePicture, name, group, totalVotes } = idol;

return (
<div className="flex items-center justify-between w-full text-[14px] pc:text-[16px] leading-[16.71px] pc:leading-[19.09px]">
<div className="flex items-center justify-center gap-[12px] font-medium">
<div className="rounded-full border-[1px] border-coralRed">
<div className="rounded-full border-[4px] border-midnightBlack">
<img
src={profilePicture}
alt={name}
className="item-center w-[60px] h-[60px] rounded-[40px]"
/>
{layout === 'default' ? (
<div className="flex w-full h-[70px] justify-between items-center">
<div className="flex items-center gap-[12px] font-medium">
<div className="rounded-full border-[1px] border-coralRed">
<div className="rounded-full border-[4px] border-midnightBlack">
<img
src={profilePicture}
alt={name}
className="items-center w-[60px] h-[60px] rounded-full"
/>
</div>
</div>
<h4 className="text-coralRed">{rank}</h4>
<div className="flex justify-between w-max">
<p className="text-white/[0.87]">
{group} {name}
</p>
</div>
</div>
<div className="font-normal text-white/60">
{totalVotes.toLocaleString()}표
</div>
</div>
) : (
<div className="flex justify-between items-center w-full py-[4px]">
<div className="flex items-center justify-center gap-[12px] font-medium">
<div className="rounded-full border-[1px] border-coralRed">
<div className="rounded-full border-[4px] border-midnightBlack">
<img
src={profilePicture}
alt={name}
className="items-center w-[60px] h-[60px] rounded-full"
/>
</div>
</div>
<h4 className="text-coralRed">{rank}</h4>
<div>
<p className="text-white/[0.87]">
{group} {name}
</p>
<div className="font-normal text-white/60 mt-[4px]">
{totalVotes.toLocaleString()}표
</div>
</div>
</div>
{children}
</div>
<h4 className="text-coralRed">{rank}</h4>
<p className="text-white/[0.87]">
{group} {name}
</p>
</div>
<div className="font-normal text-white/60">{totalVotes}표</div>
)}
</div>
);
};
Expand Down
8 changes: 2 additions & 6 deletions src/pages/listPage/monthlyChart/MonthlyChartList.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import MonthlyChartItem from '@/pages/listPage/monthlyChart/MonthlyChartItem';

const MonthlyChartList = ({ idols }) => {
if (!idols.length === 0) {
return <div>데이터가 존재하지 않습니다.</div>;
}

return (
<div className="w-full grid grid-cols-1 pc:grid-cols-2 gap-[8px] tablet:gap-[8px] pc:gap-[16px]">
{idols.map((idol) => (
{idols.map((idol, idx) => (
<div key={idol.id} className="w-full">
<MonthlyChartItem idol={idol} />
<MonthlyChartItem idol={idol} rank={idx + 1} />
<div className="w-full h-[1px] bg-white bg-opacity-10 mt-[8px] pc:mt-[16px]"></div>
</div>
))}
Expand Down
12 changes: 7 additions & 5 deletions src/pages/listPage/monthlyChart/MonthlyChartSection.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useState, useEffect } from 'react';
import chartLogo from '@/assets/icons/chartLogo.svg';
import { getLists } from '@/apis/idolListApi';
import { getLists } from '@/apis/monthlyChartApi';
import PrimaryButton from '@/components/PrimaryButton';
import MonthlyChartList from '@/pages/listPage/monthlyChart/MonthlyChartList';

const MonthlyChartSection = () => {
const [gender, setGender] = useState('female');
const MonthlyChartSection = ({ onClickVote, gender, setGender }) => {
const [cursor, setCursor] = useState(0);
const [idolData, setIdolData] = useState([]);
const [loading, setLoading] = useState(false);
Expand Down Expand Up @@ -63,13 +62,16 @@ const MonthlyChartSection = () => {
return () => {
window.removeEventListener('resize', updateChartSize);
};
}, [window.innerWidth]);
}, []);

return (
<div className="flex flex-col items-center mx-auto font-pretendard bg-midnightBlack text-white w-full pc:w-[1200px]">
<div className="flex justify-between w-full font-bold leading-[26px] mb-[16px] pc:mb-[24px] tablet:mb-[24px]">
<h3 className="text-[24px]">이달의 차트</h3>
<PrimaryButton className="flex font-pretendard pt-[2px] pb-[3px] text-[13px] tracking-[0.02em] w-[128px] h-[32px] gap-[4px] px-[12px]">
<PrimaryButton
className="flex font-pretendard pt-[2px] pb-[3px] text-[13px] tracking-[0.02em] w-[128px] h-[32px] gap-[4px] px-[12px]"
onClickFunc={onClickVote}
>
<img src={chartLogo} alt="chartLogo" className="inline" />
<span>차트 투표하기</span>
</PrimaryButton>
Expand Down