import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useParams } from "react-router-dom";
import { fetchFundingDetail } from "../../../apis/funding";
import Navbar from "../../../components/Navbar";
import { useDispatch, useSelector } from "react-redux";
import { userLogout } from "../../../redux/authSlice";
import {
MainContainer,
LeftContainer,
Logo,
P,
Button,
RightContainer,
NavbarDiv,
NavigateBtn,
NavigateDiv,
SponsorTotal,
Body,
BannerImgDiv,
BannerImg,
IllustImg,
TitleDiv,
FundingDiv,
SponserDiv,
SponsorimgDiv,
SponserComment,
SponsorCommentDiv,
FundingImgDiv,
SponsorImg,
FundingImg,
ProgressBar,
Progress,
BetweenDiv,
TogetherDiv,
FloatingButton,
} from './FundingDetailStyles';
// 펀딩 상세 페이지 컴포넌트
const FundingDetail = () => {
const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
const { id } = useParams(); // URL 매개변수(id)를 가져옴
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
const dispatch = useDispatch(); // 추가된 코드
// 펀딩 상세 정보를 담는 상태 변수 초기화
const [detailData, setDetailData] = useState({
// 초기 상태를 명세서에 따라 설정
// FundingCreate에서 받아올 Data 초기값
itemImage: '',
itemName: '',
targetAmount: 0,
publicFlag: false, // 공개, 비공개 여부
showName: '',
title: '',
content: '',
endDate: '',
// FundignDetail에 출력되는 Data 초기값
itemLink: '',
currentAmount: 0,
dday: '',
status: false,
achievementRate: 0,
ownerFlag: false, // true면 수정 페이지 버튼 보여지게
modifiedAt: '', // 수정 날짜
// 후원자 이름 추가
// 후원자 댓글 추가
});
const [sponsorDonation, setSponsorDonation] = useState({
donation5000: 5000,
donation10000: 10000,
donation20000: 20000,
donation30000: 30000,
donationInput: '직접입력',
});
//
const handledonation5000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation5000}&showName=${detailData.showName}`);
};
const handledonation10000Change = () => {
navigate(`/fundingpay/${id}?donation=${sponsorDonation.donation10000}&showName=${detailData.showName}`);
};
useEffect(() => {
// API를 호출하여 펀딩 상세 정보를 가져오는 함수 정의
const fetchData = async () => {
try {
if (!id) {
// 유효한 id가 없으면 데이터를 요청하지 않음
return;
}
// 펀딩 ID를 설정하여 특정 펀딩의 상세 정보 가져오기
// const fundingid = 1; // 예: 펀딩 ID가 1인 경우
const data = await fetchFundingDetail(id);
setDetailData(data); // 가져온 데이터를 상태 변수에 설정
} catch (error) {
if (error.response) {
const statusCode = error.response.status;
const errorMessage = error.response.data.message;
if (statusCode === 400) {
alert(errorMessage);
}
}
}
};
// 컴포넌트가 마운트될 때 API 호출 함수 실행
fetchData();
}, [id]); // 빈 배열을 전달하여 한 번만 실행하도록 설정
// 추가된 코드
const handleLogoutClick = () => {
dispatch(userLogout()); // 로그아웃 액션 디스패치
navigate('/');
};
return (
<MainContainer>
<LeftContainer>
<Logo>Giftipie</Logo>
<P pt="25px" fs="16px" fw="800" pb="5px" color="white">
기프티파이에서
</P>
<P fs="16px" fw="800" pb="5px" color="white">
정말 원하는 선물을
</P>
<P fs="16px" fw="800" color="white">
주고 받아요
</P>
<Button onClick={() => navigate('/')} mt="20px" w="180px" h="50px" fs="16px" bc="#FF7C7C">
펀딩 시작하기
</Button>
</LeftContainer>
<RightContainer>
{/* 추가된 코드 */}
<NavbarDiv>
<Navbar isLoggedIn={isLoggedIn} handleLogoutClick={handleLogoutClick} />
</NavbarDiv>
<Body>
<TitleDiv>
<P pt="20px" fs="13px" fw="800" color="gray">
{detailData.status}
</P>
<P pt="10px" fs="20px" fw="900" color="white">
{detailData.title}
</P>
<P pt="10px" pb="10px" fs="13px" fw="800" color="white">
{detailData.showName}
</P>
</TitleDiv>
<BannerImgDiv>
<IllustImg src="/imgs/Icon/right-pangpang.png" alt="img" />
<BannerImg src={detailData.itemImage} alt="image" />
<IllustImg src="/imgs/Icon/left-pangpang.png" alt="img" />
</BannerImgDiv>
<NavigateDiv>
<NavigateBtn onClick={() => navigate(`/fundingModify/${id}`)}>🖍 수정하기</NavigateBtn>
</NavigateDiv>
<TogetherDiv bc="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="#FF7C7C">
{detailData.achievementRate}%
</P>
<P pl="60px" fs="13px" fw="800" color="gray">
현재 {detailData.currentAmount}원
</P>
<P pl="30px" fs="13px" fw="800" color="gray">
{detailData.targetAmount}원
</P>
</BetweenDiv>
<BetweenDiv>
<P pt="20px" fs="13px" fw="800" color="gray">
{detailData.dday}
</P>
<P pt="20px" pb="20px" fs="13px" fw="800" color="gray">
{detailData.endDate}
</P>
</BetweenDiv>
</TogetherDiv>
<FundingDiv>
<P pt="20px" pl="23px" pb="20px" fs="16px" fw="900">
후원자
</P>
<BetweenDiv>
<SponsorImg src="/imgs/Character/iu.jpg" 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/Character/songjoongy.jpg" alt="image" />
<SponserComment mt="10px">
<P pl="5px" fs="13px" fw="800">
후원자 보여줄 이름
</P>
<SponsorCommentDiv mt="5px">줄이어폰 그만써~ 생일축하해!!</SponsorCommentDiv>
</SponserComment>
</SponserDiv>
<SponserDiv>
<SponsorImg src="/imgs/Character/junjihyun.jpg" 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="lightgray">
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Gift/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="lightgray">
<SponsorimgDiv>
<FundingImgDiv>
<FundingImg src="/imgs/Gift/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={() => navigate('/fundingpay')} mt="10px" w="100%" h="60px" bc="lightgray">
<BetweenDiv>
{/* <FundingImg src="/imgs/Gift/coffee.png" alt="image" h="40px"/> */}
<P pt="3px" fs="14px" fw="800">
이 펀딩 끝내러 왔다
</P>
<P pt="3px" fs="14px" fw="700">
{detailData.currentAmount}원
</P>
</BetweenDiv>
</Button>
<Button onClick={() => navigate('/fundingpay')} mt="10px" w="100%" h="60px" bc="lightgray">
<BetweenDiv>
{/* <FundingImg src="/imgs/Gift/coffee.png" alt="image" h="40px"/> */}
<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="black"
fs="20px"
bc="#FF7C7C"
as={FloatingButton} // FloatingButton 스타일을 적용
>
선물하기
</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;
align-items: center;
width: 500px;
height: 100vh;
margin-right: 100px;
@media (max-width: 1024px) {
display: none;
}
`;
export const Logo = styled.h1`
font-size: 30px;
font-weight: 700;
color: white;
`;
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};
align-items: center;
&:hover {
cursor: pointer;
}
`;
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: #FF7C7C;
cursor: pointer;
}
`;
export const SponsorCommentDiv = styled.div`
border-radius: 7px;
padding: 10px;
justify-content: center;
align-items: center;
background-color: #FFE6C1;
margin-top: ${(props) => props.mt};
width: 100%;
font-size: 13px;
font-weight: 600;
`
// 오른쪽 컨테이너
export const RightContainer = styled.div`
position: relative;
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
/* 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: 150px;
height: 100%;
max-height: 150px;
border-radius: 20px;
`;
export const IllustImg = styled.img`
width: 100%;
max-width: 90px;
height: 100%;
max-height: 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: 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: white;
border-radius: 20px;
border: 0.3px solid lightgray;
width: -webkit-fill-available; /* 사용 가능한 너비로 채움 */
max-width: 390px; /* 최대 너비를 390px로 제한 */
margin: 0 auto; /* 가운데 정렬을 위해 margin을 auto로 설정 */
margin-bottom: 15px;
padding: ${(props) => props.p};
@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: #dedede;
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: 20px;
border: 0.3px solid lightgray;
box-shadow: 0px 5px 0px 0px lightgray;
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 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 FloatingButton = styled.button`
position: fixed;
bottom: 0;
left: 50%; /* 뷰포트의 가운데로 이동 */
transform: translateX(-50%); /* 가운데 정렬 */
margin-bottom: 30px;
width: 220px; /* 버튼의 너비 조정 */
height: 50px; /* 버튼의 높이 조정 */
border-radius: 25px; /* 버튼의 모양을 둥글게 만듭니다. */
background-color: #FF7C7C; /* 버튼의 배경색을 지정합니다. */
color: white; /* 버튼 텍스트의 색상을 지정합니다. */
font-size: 16px; /* 버튼 텍스트의 크기를 지정합니다. */
font-weight: bold; /* 버튼 텍스트의 굵기를 지정합니다. */
border: none; /* 버튼의 테두리를 없앱니다. */
cursor: pointer; /* 버튼에 마우스를 올리면 커서를 포인터로 변경합니다. */
z-index: 1000; /* 다른 요소 위에 버튼을 표시합니다. */
`;
'React' 카테고리의 다른 글
회원가입 페이지 README 분석 (0) | 2024.03.19 |
---|---|
shadcn/ui, Zod, React Hook Form (1) | 2024.03.19 |
수정, 삭제, 완료 API 연결 (2) | 2024.02.13 |
입력한 post -> get 디테일 페이지에 출력 (1) | 2024.02.11 |
모달창 Url 입력 -> 이미지 출력 (0) | 2024.02.09 |