import React, { useEffect, useState } from "react";
import { FaChevronRight } from "react-icons/fa";
import { FaPlus } from "react-icons/fa6";
import { useNavigate } from "react-router-dom";
import LoginModal from "../Home/Login/LoginModal";
import { useDispatch, useSelector } from "react-redux";
import { bootChannelTalk } from "../../redux/channelTalkSlice";
import Navbar from "../../components/Navbar";
import { getMyFunding, getHomeFundingList } from "../../apis/home";
import { userLogout } from "../../redux/authSlice";
import theme from "../../styles/theme";
import {
MainContainer,
LeftContainer,
LeftLogoTextIcon,
LeftImg,
LeftRowdiv,
Leftcolumndiv,
LeftImgContainer,
BubbleImg,
IpadLoveImg,
P,
Button,
RightContainer,
NavbarDiv,
Body,
MainBtnContainer,
CharacterImg,
MainBtn,
BannerImg,
FundingDiv,
FundingSection,
FundingGrid,
FundingImg,
OneLine,
RoundProgressBar,
RoundProgress,
ProgressBar,
Progress,
BetweenDiv,
BannerProgressDiv,
TogetherBetween,
TogetherDiv,
TogetherImg,
TogetherGrids,
TogetherGrid,
ProductGrids,
ProductGrid,
ProductImg,
ProductBlank,
Footer,
FloatingBtn,
} from "./HomeStyles";
const Home = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn);
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
const [homeFundingList, setHomeFundingList] = useState([]);
const [myFunding, setMyFunding] = useState([
{
id: "",
itemLink: "",
itemImage: "",
itemName: "",
title: "",
showName: "",
content: "",
currentAmount: 0,
targetAmount: 0,
publicFlag: false,
endData: "",
dday: "",
status: false,
achievementRate: 0,
ownerFlag: false,
modifiedAt: "",
},
]);
const closeModal = () => setIsLoginModalOpen(false);
const handleLoginClick = () => setIsLoginModalOpen(true);
const handleLogoutClick = () => {
dispatch(userLogout());
navigate("/");
};
const handleFundingClick = (id) => {
navigate(`/fundingdetail/${id}`);
};
const handleRecentFundingClick = () => navigate("/recentfunding");
const handleFundingCreate = () => navigate("/fundingcreate");
// 내 펀딩 데이터를 가져오는 API
const getMyData = async () => {
try {
const data = await getMyFunding();
console.log("받아오고 있니? ", data);
// id가 존재할 때만 호출
if (data && Array.isArray(data)) {
const myFundingData = data.filter((funding) => funding.id);
console.log("받아오고 있는거니? ", myFundingData);
setMyFunding(myFundingData);
}
} catch (error) {
console.error("API 호출 중 에러 발생: ", error);
}
};
// 펀딩 리스트 데이터를 가져오는 API
const getData = async () => {
try {
const content = await getHomeFundingList();
setHomeFundingList(content);
} catch (error) {
console.error("펀딩 리스트 정보를 가져오는 함수 호출 실패: ", error);
}
};
useEffect(() => {
dispatch(bootChannelTalk());
getMyData();
getData();
}, [dispatch]);
const ProductGridComponent = ({
imgSrc,
altText,
brand,
itemName,
price,
}) => (
<ProductGrid>
<ProductImg src={imgSrc} alt={altText} />
<P pt="8px" fs="12px" fw="600" color="gray">
{brand}
</P>
<P pt="8px" fs="13px" fw="600">
{itemName}
</P>
<P pt="8px" pb="20px" fs="13px" fw="900">
{price}
</P>
</ProductGrid>
);
return (
<MainContainer>
<LeftContainer>
<LeftContainer pt="70px">
<LeftImgContainer>
<div>
<LeftLogoTextIcon src="/imgs/Common/giftipie.png" />
</div>
<div>
<P pt="60px" pl="355px" fs="23px" fw="800" color={theme.white}>
생일선물
<br />뭐 받고싶어?
</P>
<BubbleImg src="/imgs/Home/speech-bubble.png" />
</div>
</LeftImgContainer>
<LeftRowdiv ml="30px">
<LeftRowdiv
color={theme.gray1}
mr="10px"
bc={theme.primary}
br="25px"
p="8px"
>
<LeftImg
src="/imgs/Home/giftbox-red.png"
w="30px"
h="25px"
mr="10px"
pl="10px"
/>
<P fs="20px" fw="900" pr="10px">
정말 원하는 선물
</P>
</LeftRowdiv>
<div>
<P mt="6px" pt="2px" fs="20px" fw="700" color={theme.white}>
을 주고 받아요!
</P>
</div>
</LeftRowdiv>
<LeftRowdiv>
<Leftcolumndiv ml="30px">
<P fs="16px" fw="500" pt="30px" pb="5px" color={theme.white}>
지금은 유저테스트 진행 중 입니다
</P>
<P pb="100px" fs="16px" fw="500" color={theme.white}>
6명의 개발자와 1명의 디자이너가 함께 개발하고 있습니다
</P>
</Leftcolumndiv>
<LeftImg src="/imgs/Home/pie-hi.png" w="340px" pl="100px" />
</LeftRowdiv>
</LeftContainer>
<LeftRowdiv ml="30px"></LeftRowdiv>
<IpadLoveImg src="/imgs/Home/pie-ipad.png" w="330px" />
</LeftContainer>
<RightContainer>
<NavbarDiv>
<Navbar
isLoggedIn={isLoggedIn}
handleLoginClick={handleLoginClick}
handleLogoutClick={handleLogoutClick}
/>
</NavbarDiv>
<Body>
<TogetherDiv bc={theme.gray1}>
<BetweenDiv>
<P pt="45px" pl="50px" fs="17px" fw="800" color={theme.secondary}>
펀딩은 1개만
<br />
진행할 수 있어요
</P>
<CharacterImg src="/imgs/Home/pie-banner.png" h="20px" />
</BetweenDiv>
</TogetherDiv>
<TogetherDiv bc="white">
<BetweenDiv pt="40px">
<P pt="20px" pl="23px" pb="10px" fs="16px" fw="900">
내 펀딩
</P>
<MainBtnContainer>
<MainBtn>링크 복사</MainBtn>
<MainBtn>수정</MainBtn>
<MainBtn color={theme.primary}>삭제</MainBtn>
</MainBtnContainer>
</BetweenDiv>
{/* 내 펀딩 데이터 불러오기 */}
{myFunding.map((funding) => (
<BetweenDiv key={funding.id}>
<BannerImg src={funding.itemImage} />
<BannerProgressDiv>
<OneLine fs="11px" fw="800" color="gray">
{funding.itemName}
</OneLine>
<OneLine pt="5px" fs="13px" fw="800">
{funding.title}
</OneLine>
<P pt="10px" fs="15px" fw="900" color={theme.primary}>
{funding.achievementRate}%
</P>
<RoundProgressBar>
<RoundProgress
width={(funding.achievementRate / 100) * 100}
/>
</RoundProgressBar>
<BetweenDiv>
<P pl="0px" fs="10px" fw="800" color="gray">
현재 {funding.currentAmount}원
</P>
<P fs="10px" fw="800" color="gray">
{funding.targetAmount}원
</P>
</BetweenDiv>
</BannerProgressDiv>
</BetweenDiv>
))}
</TogetherDiv>
<TogetherDiv bc="white">
<FundingDiv>
<BetweenDiv>
<button onClick={handleRecentFundingClick}>
<P fs="16px" fw="900" pt="20px" pb="5px" pl="23px">
최근 펀딩 구경하기
<FaChevronRight />
</P>
</button>
</BetweenDiv>
<BetweenDiv>
<P fs="14px" fw="400" pl="29px" color="gray">
비공개 펀딩은 이곳에 공개되지 않아요
</P>
</BetweenDiv>
<FundingSection>
{homeFundingList.map((funding) => (
<FundingGrid
key={funding.id}
onClick={() => handleFundingClick(funding.id)}
>
<FundingImg
src={funding.itemImage}
alt={funding.itemName}
/>
<ProgressBar>
<Progress width={(funding.achievementRate / 100) * 100} />
</ProgressBar>
{/* <ProgressBar>
<Progress width={(65 / 100) * 100} />
</ProgressBar> // 퍼센트 바 스타일 확인용 */}
<BetweenDiv>
<P pt="2px" fs="13px" fw="800" color={theme.primary}>
{funding.achievementRate}%
</P>
</BetweenDiv>
<OneLine pt="10px" fs="11.5px" fw="600" color="gray">
{funding.itemName}
</OneLine>
<OneLine pt="10px" fs="12.5px" fw="600">
{funding.content}
</OneLine>
</FundingGrid>
))}
</FundingSection>
</FundingDiv>
</TogetherDiv>
<>
<TogetherBetween>
<P pt="40px" pb="40px" fs="18px" fw="600" color={theme.primary}>
Giftipie
</P>
<P pt="40px" pb="40px" fs="18px" fw="600" color="white">
에서 함께한 선물
</P>
</TogetherBetween>
<TogetherGrids>
<TogetherGrid>
<TogetherImg
src="/imgs/Common/heart-hand.png"
alt="hearthand"
/>
<P pt="10px" fs="14px" fw="400">
펀딩에
<br />
참여한 사람
</P>
<P pt="10px" pb="10px" fs="14px" fw="700">
13명
</P>
</TogetherGrid>
<TogetherGrid>
<TogetherImg
src="/imgs/Common/giftbox-yellow.png"
alt="receive"
/>
<P fs="14px" fw="400">
선물을
<br />
받은 사람
</P>
<P pt="10px" pb="10px" fs="14px" fw="700">
6명
</P>
</TogetherGrid>
<TogetherGrid>
<TogetherImg src="/imgs/Common/donation.png" alt="amount" />
<P fs="14px" fw="400">
모인
<br /> 펀딩 금액
</P>
<P pt="10px" pb="10px" fs="14px" fw="700">
1억원
</P>
</TogetherGrid>
</TogetherGrids>
</>
<TogetherDiv bc="white">
<button>
<P fs="16px" fw="900" pt="20px" pb="5px" pl="23px">
추천 상품
<FaChevronRight />
</P>
</button>
<ProductGrids>
<ProductGrid>
<ProductBlank />
</ProductGrid>
<ProductGridComponent
imgSrc="/imgs/Home/iphone15pro.jpeg"
altText="iphone"
brand="Apple"
itemName="아이폰 15 Pro 256BG 자급제"
price="1,550,000원"
/>
<ProductGridComponent
imgSrc="/imgs/Home/iphone15pro.jpeg"
altText="iphone"
brand="Apple"
itemName="아이폰 14 256BG 자급제"
price="1,090,000원"
/>
<ProductGridComponent
imgSrc="/imgs/Home/iphone15pro.jpeg"
altText="iphone"
brand="Apple"
itemName="아이폰 15 Pro 256BG 자급제"
price="1,550,000원"
/>
<ProductGridComponent
imgSrc="/imgs/Home/iphone15pro.jpeg"
altText="iphone"
brand="Apple"
itemName="아이폰 14 256BG 자급제"
price="1,090,000원"
/>
<ProductGridComponent
imgSrc="/imgs/Home/iphone15pro.jpeg"
altText="iphone"
brand="Apple"
itemName="아이폰 14 256BG 자급제"
price="1,090,000원"
/>
</ProductGrids>
</TogetherDiv>
</Body>
<Footer>
<P fs="18px" fw="600" pt="30px" pb="10px" color="lightgray">
GiftiPie란?
</P>
<P fs="14px" color="dimgray" pb="4px">
커피 기프티콘 대신, 친구가 정말로 원하는 선물을
</P>
<P fs="14px" color="dimgray" pb="50px">
함께 모금해서 선물하는 서비스예요!
</P>
<Button
onClick={handleFundingCreate}
w="100%"
h="60px"
color="black"
fs="20px"
bc="#FF7C7C"
as={FloatingBtn} // FloatingButton 스타일을 적용
>
<FaPlus />
펀딩 만들기
</Button>
</Footer>
</RightContainer>
{/* 로그인 모달 */}
{isLoginModalOpen && <LoginModal closeModal={closeModal} />}
</MainContainer>
);
};
export default Home;
import styled from "styled-components";
import theme from "../../styles/theme";
/* 전체 컨테이너 */
export const MainContainer = styled.div`
display: flex;
justify-content: center;
max-width: 1200px;
height: 100vh;
margin: 0 auto;
flex-wrap: wrap;
`;
/* 왼쪽 컨테이너 */
export const LeftContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
padding-top: ${(props) => props.pt};
@media (max-width: 1200px) {
display: none;
}
`;
export const LeftImgContainer = styled.div`
position: relative; /*상대 위치 지정*/
//width: 300px; /* 이미지 너비 */
height: 200px; /* 이미지 높이 */
padding-left: 100px; /* 이미지 왼쪽 간격 조정 */
justify-content: space-between;
`;
export const LeftLogoTextIcon = styled.img`
height: 40px;
position: absolute; /* 절대 위치 지정 */
bottom: 20px; /* 아래쪽 위치 조정 */
left: 30px; /* 왼쪽 위치 조정 */
`;
export const BubbleImg = styled.img`
position: absolute; /* 절대 위치 지정 */
top: 0; /* 위쪽 정렬 */
left: 368px; /* 왼쪽 정렬 */
width: 290px; /* 부모 요소에 대한 상대적인 너비 */
height: 230px; /* 부모 요소에 대한 상대적인 높이 */
`;
export const LeftRowdiv = styled.div`
display: flex;
flex-direction: row;
/* align-items: center; */
padding-top: ${(props) => props.pt};
margin-top: ${(props) => props.mt};
padding-bottom: ${(props) => props.pb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
margin-right: ${(props) => props.mr};
margin-left: ${(props) => props.ml};
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
color: ${(props) => props.color};
background-color: ${(props) => props.bc};
border-radius: ${(props) => props.br};
padding: ${(props) => props.p};
border: none;
`;
export const LeftImg = styled.img`
margin-top: ${(props) => props.mt};
margin-right: ${(props) => props.mr};
padding-right: ${(props) => props.pr};
padding-left: ${(props) => props.pl};
width: ${(props) => props.w};
height: ${(props) => props.h};
`;
export const Leftcolumndiv = styled.div`
flex-direction: column;
margin-left: ${(props) => props.ml};
`;
export const IpadLoveImg = styled.img`
position: absolute;
bottom: 0;
left: 0;
width: ${(props) => props.w};
height: ${(props) => props.h};
`;
/* 로고 */
export const Logo = styled.h1`
font-size: 30px;
font-weight: 700;
color: white;
`;
/* 다용도 P 태그 */
export const P = styled.p`
/* display: flex; */
padding-top: ${(props) => props.pt};
margin-top: ${(props) => props.mt};
padding-bottom: ${(props) => props.pb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
margin-right: ${(props) => props.mr};
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
color: ${(props) => props.color};
background-color: ${(props) => props.bc};
border-radius: ${(props) => props.br};
padding: ${(props) => props.p};
border: none;
align-items: center;
`;
/* 한줄만 보이게 */
export const OneLine = styled.div`
display: block;
width: 100%;
max-width: ${(props) => props.w};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
align-items: center;
color: ${(props) => props.color};
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
padding-top: ${(props) => props.pt};
padding-bottom: ${(props) => props.pb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
`;
/* 다용도 버튼 */
export const Button = styled.button`
justify-content: center;
align-items: center;
width: ${(props) => props.w};
height: ${(props) => props.h};
padding: 10px;
background-color: ${(props) => props.bc};
border-radius: 7px;
color: ${(props) => props.color};
font-size: ${(props) => props.fs};
font-weight: 600;
margin-top: ${(props) => props.mt};
margin-bottom: ${(props) => props.mb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
&:hover {
color: white;
background-color: ${theme.primary};
cursor: pointer;
}
`;
/* 오른쪽 컨테이너 */
export const RightContainer = styled.div`
position: relative;
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
/* border: 1px solid lightgray; */
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
/* 네브바 영역 */
export const NavbarDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
/* height: 70px; */
padding-left: 2px;
padding-right: 10px;
`;
/* 네브바 버튼 영역 */
export const NavbarBtnDiv = styled.div`
flex-direction: row;
padding-right: ${(props) => props.pr};
`;
/* 네브바 버튼 */
export const NavbarBtn = styled.button`
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
padding-top: ${(props) => props.pt};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
`;
export const NavbarIconContainer = styled.div`
display: flex;
align-items: center;
gap: 10px;
`;
export const NavbarNotificationIconDiv = styled.div`
font-size: 24px;
cursor: pointer;
`;
export const NavbarIconDiv = styled.div`
font-size: 24px;
cursor: pointer;
`;
export const LoginIcon = styled.img`
width: 25px;
height: 25px;
margin-top: 20px;
`;
export const LogoDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
`;
export const LogoIcon = styled.img`
height: 35px;
margin-top: 10px;
`;
// export const LeftLogoTextIcon = styled.img`
// height: 40px;
// margin-left: 10px;
// margin-top: 200px;
// `;
export const LogoTextIcon = styled.img`
height: 25px;
margin-left: 10px;
margin-top: 10px;
`;
// 바디 영역
export const Body = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
max-width: 442px;
height: auto;
`;
export const MainBtnContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
margin-right: 20px;
`;
export const MainBtn = styled.button`
justify-content: center;
align-items: center;
/* width: 130px; */
color: gray;
font-size: 10px;
color: ${(props) => props.color};
`;
export const FundingDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
max-width: 390px;
height: auto;
margin-bottom: 10px;
`;
export const FundingSection = styled.section`
display: flex;
justify-content: space-around;
flex-wrap: wrap;
width: 100%;
gap: 10px;
padding: 10px;
padding-bottom: 20px;
`;
export const EndingSection = styled.section`
display: flex;
justify-content: space-around;
flex-wrap: wrap;
width: 100%;
height: 235px;
gap: 10px;
padding: 10px;
`;
export const FundingGrid = styled.div`
width: 100%;
max-width: 110px;
overflow: hidden;
@media (max-width: 100px) {
width: 100%;
}
`;
export const CharacterImg = styled.img`
width: 100px;
margin: 20px;
`;
export const BannerImg = styled.img`
width: 100%;
max-width: 100px;
height: 100%;
max-height: 100px;
border-radius: 20px;
margin: 0px 20px 0px 25px;
/* border: 2px solid #e9e9e9; */
border: 0.3px solid ${theme.gray4};
box-shadow: 0px 0.3px 0px 0.3px ${theme.gray4};
`;
export const FundingImg = styled.img`
width: 100%;
max-width: 110px;
height: 100%;
max-height: 110px;
border: 2px solid #e9e9e9;
border-radius: 5px;
margin-top: 10px;
`;
export const ProgressBar = styled.div`
width: 100%;
max-width: 110px;
height: 5px;
background-color: #dedede;
overflow: hidden;
transform: translateY(-3px);
`;
export const Progress = styled.div`
width: ${(props) => props.width}%;
height: 5px;
padding: 0;
text-align: center;
background-color: ${theme.primary};
/* border-radius: 15px; // 추가 */
color: ${theme.primary};
`;
export const BetweenDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
max-width: ${(props) => props.mw};
max-width: 442px;
`;
export const TogetherBetween = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
width: 220px;
`;
export const TogetherDiv = styled.div`
background-color: ${(props) => props.bc};
border-radius: 30px;
border: 0.3px solid ${theme.gray4};
box-shadow: 0px 5px 0px 0px ${theme.gray4};
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
margin-bottom: 15px;
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
export const TogetherImg = styled.img`
width: 70px;
height: 70px;
margin-bottom: 10px;
`;
export const TogetherGrids = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
max-width: 390px;
margin-top: 10px;
gap: 5px;
`;
/* 프로그레스바 관련 */
export const BannerProgressDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 40px;
width: 100%;
max-width: 250px;
`;
export const RoundProgressBar = styled.div`
width: 100%;
height: 11px;
background-color: #dedede;
border-radius: 12px;
font-weight: 600;
`;
export const RoundProgress = styled.div`
width: ${(props) => props.width}%;
height: 11px;
padding: 0;
text-align: center;
background-color: ${theme.primary};
border-radius: 15px;
`;
export const TogetherGrid = styled.div`
background-color: snow;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
max-width: 115px;
height: 130px;
border-radius: 8px;
margin-bottom: 50px;
padding-bottom: 40px;
`;
export const ProductGrids = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
max-width: 390px;
gap: 10px;
margin-right: 20px;
overflow-x: scroll;
&::-webkit-scrollbar {
display: none;
}
`;
export const ProductGrid = styled.div`
width: 100%;
max-width: 100px;
@media (max-width: 110px) {
width: 100%;
}
`;
export const ProductImg = styled.img`
width: 130px;
height: 130px;
border: 2px solid #e9e9e9;
margin-top: 10px;
`;
export const ProductBlank = styled.div`
width: 150px;
height: 150px;
background-color: white;
`;
export const FundingProductGrid = styled.div`
width: 100%;
max-width: 110px;
/* overflow: hidden; */
@media (max-width: 100px) {
width: 100%;
}
`;
export const FloatingBtn = styled.button`
position: sticky;
bottom: 10px;
left: 85px;
margin-bottom: 20px;
width: 220px; /* 버튼의 너비 조정 */
height: 50px; /* 버튼의 높이 조정 */
border-radius: 25px; /* 버튼의 모양을 둥글게 만듭니다. */
background-color: ${theme.primary}; /* 버튼의 배경색을 지정합니다. */
color: ${theme.white}; /* 버튼 텍스트의 색상을 지정합니다. */
font-size: 16px; /* 버튼 텍스트의 크기를 지정합니다. */
font-weight: bold; /* 버튼 텍스트의 굵기를 지정합니다. */
border: none; /* 버튼의 테두리를 없앱니다. */
cursor: pointer; /* 버튼에 마우스를 올리면 커서를 포인터로 변경합니다. */
z-index: 1000; /* 다른 요소 위에 버튼을 표시합니다. */
`;
export const Footer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
max-width: 390px;
`;
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useParams } from "react-router-dom";
import { getFundingDetail } from "../../../apis/funding";
import Navbar from "../../../components/Navbar";
import { useDispatch, useSelector } from "react-redux";
import { userLogout } from "../../../redux/authSlice";
import theme from "../../../styles/theme";
import {
MainContainer,
LeftContainer,
LeftImgContainer,
LeftLogoTextIcon,
BubbleImg,
P,
LeftRowdiv,
LeftImg,
Leftcolumndiv,
IpadLoveImg,
Button,
RightContainer,
NavbarDiv,
NavigateBtn,
NavigateDiv,
SponsorTotal,
Body,
BannerImgDiv,
BannerImg,
IllustImg,
TitleDiv,
FundingDiv,
SponserDiv,
SponsorimgDiv,
SponserComment,
SponsorCommentDiv,
FundingImgDiv,
SponsorImg,
FundingImg,
ProgressBar,
Progress,
BetweenDiv,
TogetherDiv,
FloatingBtn,
} from './FundingDetailStyles';
const FundingDetail = () => {
const navigate = useNavigate();
const { id } = useParams();
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn);
const dispatch = useDispatch();
const [detailData, setDetailData] = useState({
itemImage: '',
itemName: '',
targetAmount: 0,
publicFlag: false, // 공개, 비공개 여부
showName: '',
title: '',
content: '',
endDate: '',
// FundignDetail에 출력되는 Data 초기값
itemLink: '',
currentAmount: 0,
dday: '',
status: false,
achievementRate: 0,
ownerFlag: false, // true면 수정 페이지 버튼 보여지게
modifiedAt: '', // 수정 날짜
sponsorNickname: '', // 후원자 이름 추가
sponsorComment: '', // 후원자 댓글 추가
donationRanking: '', // 후원자 랭킹 추가
});
const [sponsorDonation, setSponsorDonation] = useState({
donation5000: 5000,
donation10000: 10000,
donation20000: 20000,
donation30000: 30000,
donationAll: '남은금액',
donationInput: '직접입력',
});
const handledonation5000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation5000}&showName=${detailData.showName}`);
};
const handledonation10000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation10000}&showName=${detailData.showName}`);
};
const handledonation20000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation20000}&showName=${detailData.showName}`);
};
const handledonation30000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation30000}&showName=${detailData.showName}`);
};
const handledonationAllChange = () => {
setSponsorDonation({ ...sponsorDonation, donationAll: '남은금액' });
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donationAll}&showName=${detailData.showName}`);
};
const handledonationInputChange = () => {
setSponsorDonation({ ...sponsorDonation, donationInput: '직접입력' });
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donationInput}&showName=${detailData.showName}`);
};
useEffect(() => {
const getData = async () => {
try {
if (!id) {
return;
}
const data = await getFundingDetail(id);
setDetailData(data);
} catch (error) {
console.error('펀딩 상세페이지 오류:', error);
}
};
getData();
}, [id]);
const handleLogoutClick = () => {
dispatch(userLogout());
navigate('/');
};
return (
<MainContainer>
<LeftContainer>
<LeftContainer pt="70px">
<LeftImgContainer>
<div>
<LeftLogoTextIcon src="/imgs/Common/giftipie.png" />
</div>
<div>
<P pt="60px" pl="355px" fs="23px" fw="800" color={theme.white}>
생일선물
<br />뭐 받고싶어?
</P>
<BubbleImg src="/imgs/Home/speech-bubble.png" />
</div>
</LeftImgContainer>
<LeftRowdiv ml="30px">
<LeftRowdiv color={theme.gray1} mr="10px" bc={theme.primary} br="25px" p="8px">
<LeftImg src="/imgs/Home/giftbox-red.png" w="30px" h="25px" mr="10px" pl="10px" />
<P fs="20px" fw="900" pr="10px">
정말 원하는 선물
</P>
</LeftRowdiv>
<div>
<P mt="6px" pt="2px" fs="20px" fw="700" color={theme.white}>
을 주고 받아요!
</P>
</div>
</LeftRowdiv>
<LeftRowdiv>
<Leftcolumndiv ml="30px">
<P fs="16px" fw="500" pt="30px" pb="5px" color={theme.white}>
지금은 유저테스트 진행 중 입니다
</P>
<P pb="100px" fs="16px" fw="500" color={theme.white}>
6명의 개발자와 1명의 디자이너가 함께 개발하고 있습니다
</P>
</Leftcolumndiv>
<LeftImg src="/imgs/Home/pie-hi.png" w="340px" pl="100px" />
</LeftRowdiv>
</LeftContainer>
<LeftRowdiv ml="30px">
</LeftRowdiv>
<IpadLoveImg src="/imgs/Home/pie-ipad.png" w="330px" />
</LeftContainer>
<RightContainer>
<NavbarDiv>
<Navbar isLoggedIn={isLoggedIn} handleLogoutClick={handleLogoutClick} />
</NavbarDiv>
<Body>
<TitleDiv>
<P pt="20px" fs="13px" fw="800" color={theme.gray3}>
{detailData.status}
</P>
<P pt="10px" fs="20px" fw="900" color={theme.white}>
{detailData.title}
</P>
<P pt="10px" pb="10px" fs="13px" fw="800" color={theme.white}>
{detailData.showName}
</P>
</TitleDiv>
<BannerImgDiv>
<IllustImg src="/imgs/Funding/FundingDetail/pangpang-left.png" alt="img" />
<BannerImg src={detailData.itemImage} alt="image" />
<IllustImg src="/imgs/Funding/FundingDetail/pangpang-right.png" alt="img" />
</BannerImgDiv>
<NavigateDiv>
<NavigateBtn onClick={() => navigate(`/fundingModify/${id}`)}>🖍 수정하기</NavigateBtn>
</NavigateDiv>
<TogetherDiv bc={theme.white}>
<BetweenDiv pt="20px">
<P pt="5px" fs="13px" fw="900">
{detailData.itemName}
</P>
</BetweenDiv>
<ProgressBar>
<Progress width={(65 / 100) * 100} />
</ProgressBar>
<BetweenDiv>
<P fs="20px" fw="900" color={theme.primary}>
{detailData.achievementRate}%
</P>
<P pl="60px" fs="13px" fw="800" color={theme.gray3}>
현재 {detailData.currentAmount}원
</P>
<P pl="30px" fs="13px" fw="800" color={theme.gray3}>
{detailData.targetAmount}원
</P>
</BetweenDiv>
<BetweenDiv>
<P pt="20px" fs="13px" fw="800" color={theme.gray3}>
{detailData.dday}
</P>
<P pt="20px" pb="20px" fs="13px" fw="800" color={theme.gray3}>
{detailData.endDate}
</P>
</BetweenDiv>
</TogetherDiv>
<FundingDiv>
<P pt="20px" pl="23px" pb="20px" fs="16px" fw="900">
후원자
</P>
<BetweenDiv>
<SponsorImg src="/imgs/Common/profile-1.svg" alt="image" />
<SponserComment mt="10px">
<P pl="5px" fs="13px" fw="800">
후원자 보여줄 이름
</P>
<SponsorCommentDiv mt="5px">{detailData.content}</SponsorCommentDiv>
</SponserComment>
</BetweenDiv>
<SponserDiv>
<SponsorImg src="/imgs/Common/profile-2.svg" alt="image" />
<SponserComment mt="10px">
<P pl="5px" fs="13px" fw="800">
후원자 보여줄 이름
</P>
<SponsorCommentDiv mt="5px">후원자 보여줄 내용</SponsorCommentDiv>
</SponserComment>
</SponserDiv>
<SponserDiv>
<SponsorImg src="/imgs/Common/profile-3.svg" alt="img" />
<SponserComment mt="10px">
<P pl="5px" fs="13px" fw="800">
후원자 보여줄 이름
</P>
<SponsorCommentDiv mt="5px">
후원자 보여줄 내용
</SponsorCommentDiv>
</SponserComment>
</SponserDiv>
<SponsorTotal>
<P onClick={() => navigate('/fundingsponsordetail')} pt="40px" pb="20px" fs="14px" fw="800">
전체보기 ▶
</P>
</SponsorTotal>
</FundingDiv>
<FundingDiv p="20px">
<P pt="20px" pl="10px" fs="16px" fw="900">
펀딩 참여하기
</P>
<Button onClick={handledonation5000Change} mt="30px" w="100%" h="60px" bc={theme.gray4}>
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Funding/FundingDetail/coffee.png" alt="image" h="38px" ml="25px" />
</FundingImgDiv>
<BetweenDiv>
<P pt="5px" fs="14px" fw="800">
커피 한 잔 선물하기
</P>
<P pt="5px" fs="14px" fw="700">
{sponsorDonation.donation5000}원
</P>
</BetweenDiv>
</SponsorimgDiv>
</Button>
<Button onClick={handledonation10000Change} mt="10px" w="100%" h="60px" bc={theme.gray4}>
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Funding/FundingDetail/icecream.png" alt="image" h="50px" ml="10px" />
</FundingImgDiv>
<BetweenDiv>
<P pb="6px" fs="14px" fw="800">
파인트 아이스크림 선물하기
</P>
<P pb="6px" fs="14px" fw="700">
{sponsorDonation.donation10000}원
</P>
</BetweenDiv>
</SponsorimgDiv>
</Button>
<Button onClick={handledonation20000Change} mt="10px" w="100%" h="60px" bc={theme.gray4}>
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Funding/FundingDetail/chicken.png" alt="image" h="50px" ml="10px" />
</FundingImgDiv>
<BetweenDiv>
<P pb="6px" fs="14px" fw="800">
치킨 선물하기
</P>
<P pb="6px" fs="14px" fw="700">
{sponsorDonation.donation20000}원
</P>
</BetweenDiv>
</SponsorimgDiv>
</Button>
<Button onClick={handledonation30000Change} mt="10px" w="100%" h="60px" bc={theme.gray4}>
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Funding/FundingDetail/cake.png" alt="image" h="50px" ml="10px" />
</FundingImgDiv>
<BetweenDiv>
<P pb="6px" fs="14px" fw="800">
케이크 선물하기
</P>
<P pb="6px" fs="14px" fw="700">
{sponsorDonation.donation30000}원
</P>
</BetweenDiv>
</SponsorimgDiv>
</Button>
<Button onClick={handledonationAllChange} mt="10px" w="100%" h="60px" bc={theme.gray4}>
<BetweenDiv>
<P pt="3px" fs="14px" fw="800">
이 펀딩 끝내러 왔다
</P>
<P pt="3px" fs="14px" fw="700">
{detailData.currentAmount}원
</P>
</BetweenDiv>
</Button>
<Button onClick={handledonationInputChange} mt="10px" w="100%" h="60px" bc={theme.gray4}>
<BetweenDiv>
<P pt="3px" fs="14px" fw="800">
원하는 만큼 선물하기
</P>
<P pt="3px" fs="14px" fw="700">
{sponsorDonation.donationInput}
</P>
</BetweenDiv>
</Button>
</FundingDiv>
<Button
onClick={() => navigate('/fundingpay')}
w="100%"
h="60px"
color={theme.black}
fs="20px"
bc={theme.primary}
as={FloatingBtn}
>
선물하기
</Button>
</Body>
</RightContainer>
</MainContainer>
);
};
export default FundingDetail;
import styled from "styled-components";
import theme from "../../../styles/theme";
/* 전체 컨테이너 */
export const MainContainer = styled.div`
display: flex;
justify-content: center;
max-width: 1200px;
min-height: 100vh;
margin: 0 auto;
flex-wrap: wrap;
`;
/* 왼쪽 컨테이너 */
export const LeftContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
padding-top: ${(props) => props.pt};
@media (max-width: 1200px) {
display: none;
}
`;
export const LeftImgContainer = styled.div`
position: relative; /*상대 위치 지정*/
//width: 300px; /* 이미지 너비 */
height: 200px; /* 이미지 높이 */
padding-left: 100px; /* 이미지 왼쪽 간격 조정 */
justify-content: space-between;
`;
export const LeftLogoTextIcon = styled.img`
height: 40px;
position: absolute; /* 절대 위치 지정 */
bottom: 20px; /* 아래쪽 위치 조정 */
left: 30px; /* 왼쪽 위치 조정 */
`;
export const BubbleImg = styled.img`
position: absolute; /* 절대 위치 지정 */
top: 0; /* 위쪽 정렬 */
left: 368px; /* 왼쪽 정렬 */
width: 290px; /* 부모 요소에 대한 상대적인 너비 */
height: 230px; /* 부모 요소에 대한 상대적인 높이 */
`;
export const LeftRowdiv = styled.div`
display: flex;
flex-direction: row;
/* align-items: center; */
padding-top: ${(props) => props.pt};
margin-top: ${(props) => props.mt};
padding-bottom: ${(props) => props.pb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
margin-right: ${(props) => props.mr};
margin-left: ${(props) => props.ml};
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
color: ${(props) => props.color};
background-color: ${(props) => props.bc};
border-radius: ${(props) => props.br};
padding: ${(props) => props.p};
border: none;
`;
export const LeftImg = styled.img`
margin-top: ${(props) => props.mt};
margin-right: ${(props) => props.mr};
padding-right: ${(props) => props.pr};
padding-left: ${(props) => props.pl};
width: ${(props) => props.w};
height: ${(props) => props.h};
`;
export const Leftcolumndiv = styled.div`
flex-direction: column;
margin-left: ${(props) => props.ml};
`;
export const IpadLoveImg = styled.img`
position: absolute;
bottom: 0;
left: 0;
width: ${(props) => props.w};
height: ${(props) => props.h};
`;
/* 로고 */
export const Logo = styled.h1`
font-size: 30px;
font-weight: 700;
color: ${theme.white};
`;
/* 다용도 P 태그 */
export const P = styled.p`
padding-top: ${(props) => props.pt};
padding-bottom: ${(props) => props.pb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
color: ${(props) => props.color};
margin-top: ${(props) => props.mt};
margin-right: ${(props) => props.mr};
background-color: ${(props) => props.bc};
border-radius: ${(props) => props.br};
padding: ${(props) => props.p};
align-items: center;
border: none;
`;
/* 다용도 버튼 */
export const Button = styled.button`
justify-content: center;
align-items: center;
width: ${(props) => props.w};
height: ${(props) => props.h};
padding: 10px;
background-color: ${(props) => props.bc};
border-radius: 7px;
color: ${(props) => props.color};
font-size: ${(props) => props.fs};
font-weight: 600;
margin-top: ${(props) => props.mt};
margin-bottom: ${(props) => props.mb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
&:hover {
color: ${theme.white};
background-color: ${theme.primary};
cursor: pointer;
}
`;
/* 오른쪽 컨테이너 */
export const RightContainer = styled.div`
position: relative;
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
/* border: 1px solid lightgray; */
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
/* 네브바 영역 */
export const NavbarDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 70px;
`;
// 바디 영역
export const Body = styled.div`
font-size: 24px;
font-weight: 800;
height: auto;
`;
export const BannerImgDiv = styled.div`
text-align: center;
margin-bottom: 10px;
`;
export const BannerImg = styled.img`
width: 100%;
max-width: 140px;
height: 100%;
max-height: 140px;
border-radius: 20px;
`;
export const IllustImg = styled.img`
width: 100%;
max-width: 90px;
margin: 10px;
`;
export const NavigateDiv = styled.div`
text-align: right;
margin-right: 22px;
`;
export const NavigateBtn = styled.button`
font-size: 13px;
font-weight: 600;
color: ${theme.white};
margin-bottom: 7px;
`;
export const TitleDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
`;
export const FundingDiv = styled.div`
background-color: ${theme.white};
border-radius: 20px;
border: 0.3px solid ${theme.gray4};
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
margin-bottom: 15px;
padding: ${(props) => props.p};
padding-bottom: ${(props) => props.pb};
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
export const FundingNewline = styled.div`
width: 100%;
height: 12px;
`;
export const ProgressBar = styled.div`
width: 85%;
height: 15px;
background-color: ${theme.gray6};
border-radius: 12px;
font-weight: 600;
font-size: 0.8rem;
margin: 10px 30px 10px 30px;
text-align: center;
overflow: hidden;
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
`;
export const Progress = styled.div`
width: ${(props) => props.width}%;
height: 15px;
padding: 0;
text-align: center;
background-color: ${theme.primary};
border-radius: 15px;
/* color: #111; */
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
`;
export const BetweenDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
/* padding: 0px 33px 0px 33px; */
padding: 0px 33px 0px 33px;
padding-top: ${(props) => props.pt};
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
export const TogetherDiv = styled.div`
background-color: ${(props) => props.bc};
border-radius: 30px;
border: 0.3px solid ${theme.gray4};
box-shadow: 0px 5px 0px 0px ${theme.gray4};
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
margin-bottom: 15px;
@media screen and (max-width: 390px) {
max-width: 100%; /* 최대 너비를 100%로 설정하여 가득 차게 함 */
}
`;
export const SponserDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0px 33px 0px 33px;
`;
export const SponsorCommentDiv = styled.div`
border-radius: 7px;
padding: 10px;
justify-content: center;
align-items: center;
background-color: ${theme.secondary};
margin-top: ${(props) => props.mt};
width: 100%;
font-size: 13px;
font-weight: 600;
`;
export const SponserComment = styled.div`
margin-top: ${(props) => props.mt};
display: flex;
flex-direction: column;
justify-content: center;
align-items: start;
width: 100%;
`;
export const SponsorImg = styled.img`
width: 50px;
height: 50px;
border-radius: 100px;
margin: 10px;
`;
export const SponsorTotal = styled.div`
text-align: center;
`;
export const FundingImgDiv = styled.div`
height: 50px;
width: 50px;
`;
export const FundingImg = styled.img`
height: ${(props) => props.h};
margin-left: ${(props) => props.ml};
margin-bottom: ${(props) => props.mb};
margin-bottom: 1px;
`;
export const SponsorimgDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;
export const FloatingBtn = styled.button`
position: sticky;
bottom: 10px;
left: 85px;
margin-bottom: 25px;
width: 220px; /* 버튼의 너비 조정 */
height: 50px; /* 버튼의 높이 조정 */
border-radius: 25px; /* 버튼의 모양을 둥글게 만듭니다. */
background-color: ${theme.primary}; /* 버튼의 배경색을 지정합니다. */
color: ${theme.white}; /* 버튼 텍스트의 색상을 지정합니다. */
font-size: 16px; /* 버튼 텍스트의 크기를 지정합니다. */
font-weight: bold; /* 버튼 텍스트의 굵기를 지정합니다. */
border: none; /* 버튼의 테두리를 없앱니다. */
cursor: pointer; /* 버튼에 마우스를 올리면 커서를 포인터로 변경합니다. */
z-index: 1000; /* 다른 요소 위에 버튼을 표시합니다. */
`;
'Web_Project' 카테고리의 다른 글
[프로젝트 소개] Giftipie 선물펀딩 서비스 (0) | 2024.03.06 |
---|---|
생성-수정-상세-후원자-결제페이지 (0) | 2024.02.23 |
데스크탑뷰 (0) | 2024.02.18 |
생성-수정-결제페이지 (0) | 2024.02.16 |
로그인모달창, 회원가입, 로그인 (1) | 2024.02.16 |