import React, { useState } from 'react';
import { HiBell } from 'react-icons/hi';
import { BsPersonCircle } from 'react-icons/bs'; // 로그인
import { FaAngleLeft } from 'react-icons/fa6';
// import { RiLogoutBoxRLine } from "react-icons/ri";
import { IoLogOutSharp } from "react-icons/io5"; // 로그아웃
import { useNavigate } from 'react-router-dom';
import {
NavbarIconContainer,
NavbarNotificationIconDiv,
NavbarIconDiv,
NavbarBtnDiv,
NavbarBtn,
LoginIcon,
LogoIcon,
LogoTextIcon,
LogoDiv,
} from '../pages/Home/HomeStyles';
import { NotificationContainer, NotificationDiv, NotificationItem } from '../pages/Home/NotificationStyles';
const Navbar = ({ isLoggedIn, handleLoginClick, handleLogoutClick }) => {
const navigate = useNavigate();
const [isNotificationOpen, setIsNotificationOpen] = useState(false);
const [notifications, setNotifications] = useState([
{ id: 1, text: '알림1' },
{ id: 32, text: '알림2' },
{ id: 42, text: '알림3' },
{ id: 55, text: '알림4' },
{ id: 53, text: '알림5' },
{ id: 52, text: '알림6' },
{ id: 51, text: '알림7' },
]);
// 선택된 알림 아이디를 저장하는 상태
const [selectedNotifications, setSelectedNotifications] = useState([]);
const toggleNotification = () => {
setIsNotificationOpen(!isNotificationOpen);
};
const handleNotificationClick = (notification) => {
console.log(`알림 클릭: ${notification.id}`);
navigate(`/fundingdetail/${notification.id}`);
};
const handleNavbarIconClick = () => navigate('/');
// 체크박스의 상태를 변경하는 함수
const handleCheckboxChange = (notificationId) => {
setSelectedNotifications((prevSelected) =>
prevSelected.includes(notificationId)
? prevSelected.filter((id) => id !== notificationId)
: [...prevSelected, notificationId]
);
};
// 선택된 알림 삭제를 처리하는 함수
const handleDeleteSelected = () => {
setNotifications((prev) => prev.filter((notification) => !selectedNotifications.includes(notification.id)));
// 선택한 알림 초기화
setSelectedNotifications([]);
};
// 전체 알림 삭제를 처리하는 함수
const handleDeleteAll = () => {
setNotifications([]);
setSelectedNotifications([]);
toggleNotification();
};
// 상태에 따라 Navbar에 표시될 아이콘 결정
const navbarContents = isLoggedIn ? (
<>
<NavbarIconContainer>
{/* HiBell 아이콘 클릭 시 알림 리스트 표시 */}
<NavbarNotificationIconDiv onClick={toggleNotification}>
<HiBell size="" color="#FFFFFF"/>
</NavbarNotificationIconDiv>
{isNotificationOpen && (
<NotificationContainer>
<NotificationDiv>
<button onClick={toggleNotification}>
<FaAngleLeft size="" color='white'/>
</button>
<div>
<button onClick={handleDeleteSelected}>선택삭제</button>
<button onClick={handleDeleteAll}>전체삭제</button>
</div>
</NotificationDiv>
{notifications.map((notification) => (
<NotificationItem
key={notification.id}
onClick={() => handleNotificationClick(notification)}
>
{notification.text}
<input
type="checkbox"
checked={selectedNotifications.includes(notification.id)}
onChange={() => handleCheckboxChange(notification.id)}
/>
</NotificationItem>
))}
</NotificationContainer>
)}
<NavbarIconDiv>
<BsPersonCircle color="#FFFFFF"/>
</NavbarIconDiv>
<NavbarBtn onClick={handleLogoutClick} fs="13px" fw="600">
{/* <RiLogoutBoxRLine /> */}
<IoLogOutSharp size="28px" color="#FFFFFF"/>
</NavbarBtn>
</NavbarIconContainer>
</>
) : (
<>
<NavbarBtn onClick={handleLoginClick} pt="10px" fs="20px" fw="600">
<BsPersonCircle color="#FFFFFF"/>
</NavbarBtn>
</>
);
return (
<>
<NavbarBtn onClick={handleNavbarIconClick} fs="20px" fw="600" pl="25px" color="white">
<LogoDiv>
<LogoIcon src="/imgs/Icon/Frame 7413.png" />
<LogoTextIcon src="/imgs/Logo/Giftipie.png" />
</LogoDiv>
</NavbarBtn>
<NavbarBtnDiv>{navbarContents}</NavbarBtnDiv>
</>
);
};
export default Navbar;
/* 네브바 버튼 */
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 LogoTextIcon = styled.img`
height: 25px;
margin-left: 10px;
margin-top: 10px;
`;
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { fundingCreate } from "../../../apis/funding"; // 펀딩 생성 API import
import { useParams } from "react-router-dom";
import CreateModal from "./Modal/CreateModal";
import Navbar from "../../../components/Navbar"; // 추가된 코드
import { useDispatch, useSelector } from "react-redux"; // 추가된 코드
import { userLogout } from "../../../redux/authSlice"; // 추가된 코드
import {
MainContainer,
LeftContainer,
Logo,
P,
Button,
RightContainer,
NavbarDiv,
ProducImgtDiv,
InputTag,
FundingImg,
Body,
FundingDiv,
SponserDiv,
RadioInput,
SponserComment,
TogetherDiv,
SponsorComment,
ImgText,
} from "./FundingCreateStyles";
// 펀딩 생성 페이지 컴포넌트
const FundingCreate = () => {
const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
const { id } = useParams(); // URL 매개변수(id)를 가져옴
const [itemImage, setItemImage] = useState(false);
const [isFundingModalOpen, setIsFundingModalOpen] = useState(false); // 모달 창의 열림 여부 상태 변수
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn);
const dispatch = useDispatch();
// 펀딩 생성 페이지에서 사용될 상태 변수 초기화
const [createData, setCreateData] = useState({
itemName: "",
targetAmount: "",
publicFlag: true,
showName: "",
title: "",
content: "",
endDate: "",
});
// 펀딩 이미지를 클릭했을 때 모달을 열고 이미지를 설정하는 함수
const handleFundingModalClick = (e) => {
setIsFundingModalOpen(true);
};
// 모달을 닫는 함수
const closeModal = () => {
setIsFundingModalOpen(false);
};
// 모달 내에서 이미지를 선택하고 설정하는 함수
const handleImageSelection = (itemImage) => {
setItemImage(itemImage);
setIsFundingModalOpen(false); // 이미지 선택 후 모달을 닫습니다.
};
// 각 입력값에 대한 상태 업데이트 핸들러
const handleItemNameChange = (e) => {
setCreateData({ ...createData, itemName: e.target.value });
};
const handleTargetAmountChange = (e) => {
setCreateData({ ...createData, targetAmount: e.target.value });
};
const handleShowNameChange = (e) => {
setCreateData({ ...createData, showName: e.target.value });
};
const handleTitleChange = (e) => {
setCreateData({ ...createData, title: e.target.value });
};
const handleContentChange = (e) => {
setCreateData({ ...createData, content: e.target.value });
};
const handleEndDateChange = (e) => {
setCreateData({ ...createData, endDate: e.target.value });
};
const handlePublicFlagChange = (e) => {
// 업데이트: 한 번에 하나의 옵션만 선택했는지 확인하세요.
const value = e.target.value === "true" ? true : false;
setCreateData({ ...createData, publicFlag: value });
};
// 펀딩 생성 요청 처리 함수
const handleFundingClick = async () => {
try {
if (
itemImage === "" ||
createData.itemName === "" ||
createData.targetAmount === "" ||
createData.publicFlag === "" ||
createData.showName === "" ||
createData.title === "" ||
createData.content === "" ||
createData.endDate === ""
) {
alert("내용을 입력해주세요");
return;
}
// 펀딩 생성 API 호출 및 데이터 전송
const response = await fundingCreate({
id,
itemImage,
itemName: createData.itemName,
targetAmount: createData.targetAmount,
publicFlag: createData.publicFlag,
showName: createData.showName,
title: createData.title,
content: createData.content,
endDate: createData.endDate,
});
console.log("펀딩 생성 성공:", response);
navigate(`/fundingdetail/${response.id}`);
} catch (error) {
if (error.response) {
const statusCode = error.response.status;
const errorMessage = error.response.data.message;
if (statusCode === 400) {
// alert(errorMessage);
alert("펀딩 생성 실패 :", errorMessage);
}
}
}
};
// 추가된 코드
const handleLogoutClick = () => {
dispatch(userLogout()); // 로그아웃 액션 디스패치
navigate("/");
};
return (
<MainContainer>
<LeftContainer>
<Logo>Giftipie</Logo>
<P pt="25px" fs="16px" fw="800" pb="5px">
기프티파이에서
</P>
<P fs="16px" fw="800" pb="5px">
정말 원하는 선물을
</P>
<P fs="16px" fw="800">
주고 받아요
</P>
</LeftContainer>
<RightContainer>
{/* 추가된 코드 */}
<NavbarDiv>
<Navbar
isLoggedIn={isLoggedIn}
handleLogoutClick={handleLogoutClick}
/>
</NavbarDiv>
<Body>
<form
onSubmit={(e) => {
e.preventDefault();
}}
>
<FundingDiv>
<P pb="10px" fs="16px" fw="900" color="#FF7C7C">
펀딩 생성페이지
</P>
<P pb="20px" fs="10px" fw="900" color="#E4E4E4">
펀딩 생성 페이지에 상품명과 이미지가 노출돼요.
</P>
<ProducImgtDiv>
<SponsorComment
mt="10px"
pointer="pointer"
onClick={handleFundingModalClick}
>
<FundingImg src={itemImage} h="90px" w="80px" />
<ImgText>상품 링크 URL</ImgText>
</SponsorComment>
<div>
<InputTag
type="text"
value={createData.itemName}
onChange={handleItemNameChange}
placeholder="상품명을 입력해주세요"
h="40px"
w="97%"
ml="10px"
mb="10px"
pl="10px"
/>
<InputTag
type="text"
value={createData.targetAmount}
onChange={handleTargetAmountChange}
placeholder="가격을 입력해주세요"
h="40px"
w="97%"
ml="10px"
pl="10px"
/>
</div>
</ProducImgtDiv>
{/* 모달 컴포넌트 표시 여부 확인 후 표시 */}
{isFundingModalOpen && (
<CreateModal
closeModal={closeModal}
handleImageSelection={handleImageSelection}
/>
)}
{/* 펀딩 내용 및 공개 여부 입력 폼 */}
<SponserDiv>
<SponserComment mt="50px">
<P pb="10px" fs="16px" fw="900" color="#FF7C7C">
펀딩 내용
</P>
<P pb="20px" fs="13px" fw="900" color="#E4E4E4">
공개 방식을 설정해주세요.
</P>
<SponserDiv>
<RadioInput
value="true"
checked={createData.publicFlag === true}
onChange={handlePublicFlagChange}
type="radio"
mb="21px"
/>
<P pb="20px" fs="13px" fw="900" pl="20px" color="#E4E4E4">
공개
</P>
<P pb="20px" fs="10px" fw="900" pl="42px" color="#E4E4E4">
누구나 볼 수 있어요
</P>
</SponserDiv>
<SponserDiv>
<RadioInput
value="false"
checked={createData.publicFlag === false}
onChange={handlePublicFlagChange}
type="radio"
mb="21px"
/>
<P pb="20px" fs="13px" fw="900" pl="20px" color="#E4E4E4">
비공개
</P>
<P pb="20px" fs="10px" fw="900" pl="30px" color="#E4E4E4">
링크를 통해서만 방문할 수 있어요
</P>
</SponserDiv>
</SponserComment>
</SponserDiv>
<P pt="30px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
보여줄 이름
</P>
<InputTag
type="text"
value={createData.showName}
onChange={handleShowNameChange}
placeholder="이름을 입력해주세요"
h="40px"
w="97%"
mb="10px"
pl="10px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
제목
</P>
<InputTag
type="text"
value={createData.title}
onChange={handleTitleChange}
placeholder="제목을 입력해주세요"
h="40px"
w="97%"
mb="10px"
pl="10px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
본문
</P>
<InputTag
type="text"
value={createData.content}
onChange={handleContentChange}
placeholder="본문을 입력해주세요"
h="90px"
w="97%"
mb="10px"
pl="10px"
pb="50px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
마감일 설정
</P>
<InputTag
type="date"
value={createData.endDate}
onChange={handleEndDateChange}
h="40px"
w="97%"
pl="10px"
pt="10px"
/>
</FundingDiv>
<TogetherDiv>
<P pl="130px" fs="14px" fw="800" color="#FFE6C1">
펀딩 금액은 계좌로 전달돼요
</P>
<P pl="95px" fs="14px" fw="800" color="#FFE6C1">
펀딩에 성공하면 카톡으로 알림이 가요
</P>
</TogetherDiv>
<Button
onClick={handleFundingClick}
w="442px"
h="60px"
mt="10px"
color="white"
fs="19px"
bc="#FF7C7C"
>
펀딩 등록하기
</Button>
</form>
</Body>
</RightContainer>
</MainContainer>
);
};
export default FundingCreate;
import styled from "styled-components";
// 전체 컨테이너
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;
padding: 20px;
/* border: 1px solid lightgray; */
border-radius: 8px;
margin-right: 100px;
@media (max-width: 1024px) {
display: none;
}
`;
export const Logo = styled.h1`
font-size: 24px;
font-weight: 800;
`;
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;
`;
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: black;
cursor: pointer;
}
`;
// 오른쪽 컨테이너
export const RightContainer = styled.div`
position: relative;
width: 442px;
border: 1px solid lightgray;
border-radius: 20px;
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media (max-width: 442px) {
width: 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 FundingDiv = styled.div`
justify-content: center;
width: 100%;
max-width: 442px;
height: auto;
padding: 30px;
`;
export const ProducImgtDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;
export const SponserDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;
export const SponserComment = styled.div`
margin-top: ${(props) => props.mt};
display: flex;
flex-direction: column;
justify-content: center;
align-items: start;
`;
export const FundingImg = styled.img`
width: ${(props) => props.w};
height: ${(props) => props.h};
padding-left: ${(props) => props.pl};
border-radius: 4px;
border: none;
background-color: #eae7de;
font-weight: 500;
font-size: 12px;
justify-content: start;
align-items: start;
&:hover {
cursor: pointer;
}
`;
export const SponsorComment = styled.div`
margin-top: ${(props) => props.mt};
border: none;
display: flex;
flex-direction: column;
justify-content: start;
align-items: start;
&:hover {
cursor: ${(props) => props.pointer};
}
`;
export const ImgText = styled.h1`
/* position: absolute; 핵심코드 */
top: 47%; // 핵심코드
right: 25%; //핵심코드 */
transform: translate( 10%, -140%); // 핵심코드
color: gray;
`;
export const InputTag = styled.input`
width: ${(props) => props.w};
height: ${(props) => props.h};
background-color: #eae7de;
border-radius: 4px;
border: none;
margin-left: ${(props) => props.ml};
margin-bottom: ${(props) => props.mb};
padding-left: ${(props) => props.pl};
padding-top: ${(props) => props.pt};
padding-bottom: ${(props) => props.pb};
font-weight: 500;
font-size: 12px;
justify-content: start;
align-items: start;
`;
export const RadioInput = styled.input`
margin-bottom: ${(props) => props.mb};
accent-color: black;
`;
export const FundingNewline = styled.div`
width: 100%;
height: 12px;
`;
export const TogetherDiv = styled.div`
margin-top: 30px;
width: 442px;
height: 45px;
background-color: ${(props) => props.bc};
color: ${(props) => props.color};
justify-content: center;
align-items: center;
`;
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom"; // React Router에서 네비게이션 기능을 사용하기 위한 hook
import { useParams } from "react-router-dom"; // React Router에서 URL 매개변수를 가져오기 위한 hook
import Navbar from "../../../components/Navbar"; // 추가된 코드
import { useDispatch, useSelector } from "react-redux"; // 추가된 코드
import { userLogout } from "../../../redux/authSlice"; // 추가된 코드
import {
updateFundingModify,
deleteFundingModify,
FundingModifyGet,
completeFundingModify,
} from "../../../apis/funding"; // 펀딩 수정 API, 펀딩 상세 정보 API
import {
MainContainer,
LeftContainer,
Logo,
P,
Button,
NavbarDiv,
RightContainer,
InputTag,
Body,
FundingDiv,
SponsorDiv,
RadioInput,
SponsorComment,
FundingImg,
// ImgText,
TogetherDiv,
} from "./FundingModifyStyles"; // 스타일 컴포넌트 import
// 펀딩 수정 페이지 컴포넌트
const FundingModify = () => {
const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
const { id } = useParams(); // URL 매개변수(id)를 가져옴
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
const dispatch = useDispatch(); // 추가된 코드
// 펀딩 데이터 상태와 상태 설정 함수 초기화
const [fundingData, setFundingData] = useState({
itemName: "",
showName: "",
title: "",
content: "",
targetAmount: 0,
publicFlag: "",
endDate: "",
itemImage: "",
});
// 추가된 코드
const handleLogoutClick = () => {
dispatch(userLogout()); // 로그아웃 액션 디스패치
navigate("/");
};
// const [isFundingModalOpen, setIsFundingModalOpen] = useState(false); // 모달 창의 열림 여부 상태 변수
// 펀딩 이미지를 클릭하여 모달을 열고 이미지를 설정하는 함수
// const handleFundingModalClick = (e) => {
// setIsFundingModalOpen(true);
// };
// 모달을 닫는 함수
// const closeModal = () => {
// setIsFundingModalOpen(false);
// // setItemImage(''); // 이미지 상태를 초기화하여 이미지를 숨김
// };
// 모달 내에서 이미지를 선택하고 설정하는 함수
// const handleImageSelection = (itemImage) => {
// setFundingData(itemImage);
// setIsFundingModalOpen(false); // 이미지 선택 후 모달 닫기
// };
useEffect(() => {
// API를 호출하여 펀딩 상세 정보를 가져오는 함수 정의
const fetchData = async () => {
try {
if (!id) {
// 유효한 id가 없으면 데이터를 요청하지 않음
return;
}
const data = await FundingModifyGet(id); // 펀딩 상세 정보 가져오기
setFundingData(data); // 가져온 데이터를 상태 변수에 설정
console.log("펀딩상세 가져오기 성공", data);
} catch (error) {
console.error("펀딩상세 가져오기 오류:", error);
}
};
// 컴포넌트가 마운트될 때 API 호출 함수 실행
fetchData();
}, [id]); // 빈 배열을 전달하여 한 번만 실행하도록 설정
// 펀딩 수정 요청 함수
const handlefundingModifyClick = async () => {
try {
if (
fundingData.publicFlag === "" ||
fundingData.showName === "" ||
fundingData.title === "" ||
fundingData.content === ""
) {
alert("내용을 입력해주세요");
return;
}
const data = await updateFundingModify(id, fundingData); // 펀딩 수정 API 호출
// setFundingData(fundingData.map((data) => {
// if (data.id === id) {
// return { ...data, fundingData };
// } else {
// return data;
// }
// }))
console.log("펀딩 수정 성공:", data);
navigate(`/fundingdetail/${data.id}`); // 펀딩 상세 페이지로 이동
} catch (error) {
if (error.response) {
const statusCode = error.response.status;
const errorMessage = error.response.data.message;
if (statusCode === 400) {
alert("펀딩 수정 실패 :", errorMessage);
}
}
}
};
const handledeleteFundingClick = async () => {
try {
const confirmDelete = window.confirm("정말 삭제하시겠습니까?");
if (!confirmDelete) return;
await deleteFundingModify(id, fundingData);
console.log("펀딩 삭제 성공:", id);
navigate(`/`);
// if (id) {
// alert('정말 삭제하시겠습니까?');
// return;
// }
// const data = await deleteFundingModify(id, fundingData);
// const data = await deleteFundingModify(id);
// setFundingData(
// fundingData.filter((data) => {
// return data.id !== id;
// })
// );
// console.log('펀딩 삭제 성공:', data);
// navigate(`/`);
} catch (error) {
console.error("펀딩 삭제 실패:", error);
// 에러 핸들링
}
};
const handlecompleteFundingClick = async () => {
try {
if (!id) {
// 유효한 id가 없으면 데이터를 요청하지 않음
return;
}
const data = await completeFundingModify(id); // 펀딩 상세 정보 가져오기
setFundingData(data); // 가져온 데이터를 상태 변수에 설정
console.log("펀딩 종료 성공", data);
navigate(`/`);
} catch (error) {
console.error("펀딩 종료 오류:", error);
}
};
// UI 렌더링
return (
<MainContainer>
{/* 왼쪽 컨테이너 */}
<LeftContainer>
{/* 로고 및 간단한 설명 */}
<Logo>Giftipie</Logo>
<P pt="25px" fs="16px" fw="800" pb="5px">
기프티파이에서
</P>
<P fs="16px" fw="800" pb="5px">
정말 원하는 선물을
</P>
<P fs="16px" fw="800">
주고 받아요
</P>
{/* 펀딩 시작하기 버튼 */}
</LeftContainer>
{/* 오른쪽 컨테이너 */}
<RightContainer>
{/* 추가된 코드 */}
<NavbarDiv>
<Navbar
isLoggedIn={isLoggedIn}
handleLogoutClick={handleLogoutClick}
/>
</NavbarDiv>
{/* 펀딩 수정 내용 입력 부분 */}
<Body>
{/* 펀딩 상품 정보 입력 및 이미지 변경 */}
<FundingDiv>
{/* 펀딩 페이지에 노출되는 상품명 및 이미지 변경 버튼 */}
<P pb="10px" fs="16px" fw="900" color="#FF7C7C">
펀딩 수정페이지
</P>
<P pb="20px" fs="10px" fw="900" color="#E4E4E4">
펀딩페이지의 상품명, 가격, 이미지는 변경할 수 없습니다.
</P>
<SponsorDiv>
{/* <SponsorComment pointer="pointer" onClick={handleFundingModalClick}> */}
{/* <FundingImg onClick={handleFundingModalClick} src={fundingData.itemImage} alt="logo"/> */}
<FundingImg src={fundingData.itemImage} alt="logo" />
{/* <ImgText>이미지 변경</ImgText> */}
{/* </SponsorComment> */}
<SponsorComment mt="10px">
<div>
<InputTag
type="text"
placeholder="상품명을 입력해주세요"
value={fundingData.itemName}
// onChange={(e) => {
// setFundingData({ ...fundingData, itemName: e.target.value });
// }}
h="40px"
w="92%"
ml="10px"
mb="10px"
pl="10px"
/>
<InputTag
type="text"
placeholder="가격을 입력해주세요"
value={fundingData.targetAmount}
// onChange={(e) => {
// setFundingData({ ...fundingData, targetAmount: e.target.value });
// }}
h="40px"
w="92%"
ml="10px"
pl="10px"
/>
</div>
</SponsorComment>
{/* 모달 컴포넌트 표시 여부 확인 후 표시 */}
{/* {isFundingModalOpen && (
<ModifyModal closeModal={closeModal} handleImageSelection={handleImageSelection} />
)} */}
</SponsorDiv>
{/* 펀딩 내용 및 공개 여부 입력 부분 */}
<SponsorDiv>
<SponsorComment mt="50px">
<P pb="10px" fs="16px" fw="900" color="#FF7C7C">
펀딩 내용
</P>
<P pb="20px" fs="13px" fw="900" color="#E4E4E4">
공개 방식을 설정해주세요.
</P>
<SponsorDiv>
<RadioInput
value="true"
checked={fundingData.publicFlag === "true"}
onChange={(e) => {
setFundingData({
...fundingData,
publicFlag: e.target.value,
});
}}
type="radio"
mb="21px"
/>
<P pb="20px" fs="13px" fw="900" pl="20px" color="#E4E4E4">
공개
</P>
<P pb="20px" fs="10px" fw="900" pl="42px" color="#E4E4E4">
누구나 볼 수 있어요
</P>
</SponsorDiv>
<SponsorDiv>
<RadioInput
value="false"
checked={fundingData.publicFlag === "false"}
onChange={(e) => {
setFundingData({
...fundingData,
publicFlag: e.target.value,
});
}}
type="radio"
mb="21px"
/>
<P pb="20px" fs="13px" fw="900" pl="20px" color="#E4E4E4">
비공개
</P>
<P pb="20px" fs="10px" fw="900" pl="30px" color="#E4E4E4">
링크를 통해서만 방문할 수 있어요
</P>
</SponsorDiv>
</SponsorComment>
</SponsorDiv>
<P pt="30px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
이름
</P>
<InputTag
type="text"
placeholder="이름을 입력해주세요"
value={fundingData.showName}
onChange={(e) => {
setFundingData({ ...fundingData, showName: e.target.value });
}}
h="40px"
w="97%"
mb="10px"
pl="10px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
제목
</P>
<InputTag
type="text"
placeholder="제목을 입력해주세요"
value={fundingData.title}
onChange={(e) => {
setFundingData({ ...fundingData, title: e.target.value });
}}
h="40px"
w="97%"
mb="10px"
pl="10px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
본문
</P>
<InputTag
type="text"
placeholder="본문을 입력해주세요"
value={fundingData.content}
onChange={(e) => {
setFundingData({ ...fundingData, content: e.target.value });
}}
h="90px"
w="97%"
mb="10px"
pl="10px"
pb="50px"
/>
<P pt="10px" pb="5px" fs="13px" fw="800" color="#E4E4E4">
마감일 설정
</P>
<InputTag
type="date"
value={fundingData.endDate}
// onChange={(e) => {
// setFundingData({ ...fundingData, endDate: e.target.value });
// }}
h="40px"
w="97%"
pl="10px"
pt="10px"
/>
</FundingDiv>
{/* 펀딩 안내 문구 */}
<TogetherDiv>
<P pl="130px" fs="14px" fw="800" color="#FFE6C1">
펀딩 금액은 계좌로 전달돼요
</P>
<P pl="95px" fs="14px" fw="800" color="#FFE6C1">
펀딩에 성공하면 카톡으로 알림이 가요
</P>
</TogetherDiv>
{/* 펀딩 변경하기 및 펀딩 종료하기 버튼 */}
<Button
onClick={handlefundingModifyClick}
w="442px"
h="60px"
mt="10px"
color="white"
fs="19px"
bc="gray"
>
펀딩 변경하기
</Button>
<Button
onClick={handlecompleteFundingClick}
w="442px"
h="60px"
mt="10px"
color="#5F5F5F"
fs="19px"
bc="#FFE6C1"
>
펀딩 종료하기
</Button>
<Button
onClick={handledeleteFundingClick}
w="442px"
h="60px"
mt="10px"
color="white"
fs="19px"
bc="#FF7C7C"
>
펀딩 삭제하기
</Button>
</Body>
</RightContainer>
</MainContainer>
);
};
export default FundingModify;
import styled from "styled-components";
// 전체 컨테이너
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;
padding: 20px;
margin-right: 100px;
@media (max-width: 1024px) {
display: none;
}
`;
export const Logo = styled.h1`
font-size: 24px;
font-weight: 800;
`;
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;
`;
export const Button = styled.button`
justify-content: center;
align-items: center;
width: ${(props) => props.w};
height: ${(props) => props.h};
padding: ${(props) => props.p};
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: black;
cursor: pointer;
}
`;
// 오른쪽 컨테이너
export const RightContainer = styled.div`
position: relative;
width: 442px;
border: 1px solid lightgray;
border-radius: 20px;
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media (max-width: 442px) {
width: 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 FundingDiv = styled.div`
justify-content: center;
width: 100%;
max-width: 442px;
height: auto;
padding: 30px;
`;
export const SponsorDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;
export const SponsorComment = styled.div`
margin-top: ${(props) => props.mt};
display: flex;
flex-direction: column;
justify-content: start;
align-items: start;
&:hover {
cursor: ${(props) => props.pointer};
}
`;
export const FundingProductImg = styled.img`
width: 90px;
height: 90px;
border-radius: 4px;
margin-top: 10px;
`;
export const FundingImg = styled.img`
max-width: 90px;
max-height: 100px;
width: 100%;
height: 100%;
border-radius: 8px;
margin-top: 10px;
`;
export const ImgText = styled.h1`
/* position: absolute; 핵심코드 */
top: 47%; // 핵심코드
right: 25%; //핵심코드 */
transform: translate(15%, -130%); // 핵심코드
color: gray;
`;
export const InputTag = styled.input`
width: ${(props) => props.w};
height: ${(props) => props.h};
background-color: #eae7de;
border-radius: 4px;
border: none;
margin-left: ${(props) => props.ml};
margin-bottom: ${(props) => props.mb};
padding-left: ${(props) => props.pl};
padding-top: ${(props) => props.pt};
padding-bottom: ${(props) => props.pb};
font-weight: 500;
font-size: 12px;
justify-content: start;
align-items: start;
`;
export const RadioInput = styled.input`
margin-bottom: ${(props) => props.mb};
accent-color: black;
`;
export const FundingNewline = styled.div`
width: 100%;
height: 12px;
`;
export const TogetherDiv = styled.div`
margin-top: 30px;
width: 442px;
height: 45px;
background-color: ${(props) => props.bc};
color: ${(props) => props.color};
justify-content: center;
align-items: center;
`;
import React, { useState, useEffect } from "react";
import { useNavigate, useParams, useLocation } from "react-router-dom";
import CheckBox from "../FundingPay/CheckBox/CheckBox";
import { warnToast } from "../../../components/toast";
import { useDispatch, useSelector } from "react-redux"; // 추가된 코드
import { userLogout } from "../../../redux/authSlice"; // 추가된 코드
import Navbar from "../../../components/Navbar"; // 추가된 코드
import {
fundingPayDonationReady,
getDonationApproval,
getFundingDonation,
} from "../../../apis/funding";
import {
MainContainer,
LeftContainer,
Logo,
P,
Button,
NavbarDiv,
RightContainer,
SponserMoney,
InputTag,
Body,
FundingDiv,
SponserDiv,
SponserComment,
SponsorImg,
TogetherDiv,
KakaoButton,
KakaoPayLogo,
} from "./FundingPayStyles";
const FundingPay = () => {
const navigate = useNavigate();
const { id } = useParams();
const location = useLocation();
const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
const dispatch = useDispatch(); // 추가된 코드
// 후원자 정보 및 펀딩 정보를 관리할 상태 변수들을 설정
const [sponsorDonation, setSponsorDonation] = useState({
showName: "",
donation: "",
donationRanking: "",
sponsorNickname: "",
sponsorComment: "",
});
// useEffect를 이용하여 URL 매개변수에서 donation, showName 값을 가져오는 부분 합침
useEffect(() => {
const fetchData = async () => {
try {
if (!id) {
return;
}
const params = new URLSearchParams(location.search);
const donation = params.get("donation");
const showName = params.get("showName");
// 특정 펀딩의 상세 정보를 가져오기
const response = await getFundingDonation(id);
// 후원자 정보 업데이트
setSponsorDonation((prev) => ({
...prev,
donation: donation ? parseInt(donation) : "",
showName: showName || prev.showName,
donationRanking: response.result.donationRanking,
}));
console.log("펀딩 랭킹 가져오기:", response);
} catch (error) {
console.error("결제 오류:", error);
}
};
// 컴포넌트가 마운트될 때와 id가 변경될 때 API 호출 함수 실행
fetchData();
}, [id, location.search]);
const handleFundingDonationClick = async () => {
try {
if (
sponsorDonation.sponsorNickname === "" ||
sponsorDonation.sponsorComment === ""
) {
warnToast("내용을 입력해주세요");
return;
}
// 결제 준비 API
const response = await fundingPayDonationReady({
id,
sponsorNickname: sponsorDonation.sponsorNickname,
sponsorComment: sponsorDonation.sponsorComment,
donation: sponsorDonation.donation,
});
// 리다이렉션을 원하면
window.location.href = response.result.next_redirect_pc_url;
} catch (error) {
console.error("결제 준비 오류:", error);
}
};
// 결제 승인 API
useEffect(() => {
const fetchData = async () => {
try {
// 여기에서 window.location.href 사용하면서 변경된 부분
console.log("API 호출 전");
const response = await getDonationApproval();
console.log("페이지에서 결제 승인 성공: ", response);
// 여기에서 상태를 업데이트하거나 다른 작업을 수행할 수 있습니다.
} catch (error) {
console.error("페이지에서 결제 승인 오류:", error);
// 오류가 발생한 경우에 대한 처리를 여기에 추가할 수 있습니다.
}
};
// 여기에서도 window.location.href를 사용하면서 변경된 부분
if (window.location.href.includes("redirected=true")) {
console.log("fetchData 호출 전");
fetchData();
} else {
console.error(
"에러: pgToken이 비어있습니다. 결제 승인이 처리되지 않습니다."
);
}
}, []);
// 추가된 코드
const handleLogoutClick = () => {
dispatch(userLogout()); // 로그아웃 액션 디스패치
navigate("/");
};
return (
<MainContainer>
<LeftContainer>
<Logo>Giftipie</Logo>
<P pt="25px" fs="16px" fw="800" pb="5px">
기프티파이에서
</P>
<P fs="16px" fw="800" pb="5px">
정말 원하는 선물을
</P>
<P fs="16px" fw="800">
주고 받아요
</P>
<Button
onClick={() => navigate("/")}
mt="20px"
w="180px"
h="50px"
fs="16px"
color="#2C2C2C"
bc="#FF7C7C"
>
Home
</Button>
</LeftContainer>
<RightContainer>
{/* 추가된 코드 */}
<NavbarDiv>
<Navbar
isLoggedIn={isLoggedIn}
handleLogoutClick={handleLogoutClick}
/>
</NavbarDiv>
<Body>
<FundingDiv>
<SponserMoney>
{/* <SponsorImg src="/imgs/junjihyun.jpg" alt="logo" /> */}
<P pt="10px" fs="16px" fw="800" pb="5px" color="#FFFFFF">
{sponsorDonation.showName} 님에게
</P>
<P fs="16px" fw="800" pb="5px" color="#FFFFFF">
{sponsorDonation.donation}원
</P>
<P fs="16px" fw="800" color="#FFFFFF">
후원하기
</P>
</SponserMoney>
<P pt="20px" pb="20px" fs="16px" fw="900" color="#FFFFFF">
후원자
</P>
<SponserDiv>
<SponserComment mt="10px">
<P pl="10px" pb="5px" fs="13px" fw="800" color="#FFFFFF">
이름
</P>
<InputTag
type="text"
placeholder="남길 이름을 입력해주세요"
value={sponsorDonation.sponsorNickname}
onChange={(e) => {
setSponsorDonation({
...sponsorDonation,
sponsorNickname: e.target.value,
});
}}
h="40px"
/>
<P pl="10px" fs="10px" fw="800" color="#FFFFFF">
주최자에게 이름이 모두 공개되고, 후원자 목록에는 두번째
글자부터 *으로 표시됩니다. 예) 김 * *
</P>
</SponserComment>
</SponserDiv>
<P pt="10px" pl="10px" pb="5px" fs="13px" fw="800" color="#FFFFFF">
메시지
</P>
<InputTag
type="text"
placeholder="남길 메시지를 입력해주세요"
value={sponsorDonation.sponsorComment}
onChange={(e) => {
setSponsorDonation({
...sponsorDonation,
sponsorComment: e.target.value,
});
}}
pb="50px"
h="100px"
/>
<P pl="10px" fs="10px" fw="800" color="#FFFFFF">
현재는 테스트 기간으로, 실제 결제가 이루어지지 않습니다. 대신
1명이 참여할 때마다 개설자에게 1,000원이 적립됩니다.
</P>
</FundingDiv>
<CheckBox />
<TogetherDiv pt="10px">
<P pl="140px" pt="11px" pb="19px" fs="14px" fw="800" bc="#FF7C7C">
지금 선물하면 {sponsorDonation.donationRanking}등이에요!
</P>
</TogetherDiv>
<KakaoButton onClick={handleFundingDonationClick}>
<KakaoPayLogo src="/imgs/Logo/kakaopay.png" alt="image"/>
</KakaoButton>
</Body>
</RightContainer>
</MainContainer>
);
};
export default FundingPay;
import styled from "styled-components";
// 전체 컨테이너
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;
padding: 20px;
margin-right: 100px;
@media (max-width: 1024px) {
display: none;
}
`;
export const Logo = styled.h1`
font-size: 24px;
font-weight: 800;
`;
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};
background-color: ${(props) => props.bc};
align-items: center;
`;
export const Button = styled.button`
justify-content: center;
align-items: center;
width: ${(props) => props.w};
height: ${(props) => props.h};
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: black;
cursor: pointer;
}
`;
// 네브바 영역
export const NavbarDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 70px;
`;
// 오른쪽 컨테이너
export const RightContainer = styled.div`
position: relative;
width: 442px;
border: 1px solid lightgray;
border-radius: 20px;
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media (max-width: 442px) {
width: 100%;
}
`;
// 바디 영역
export const Body = styled.div`
font-size: 24px;
font-weight: 800;
height: 2100px;
`;
export const FundingDiv = styled.div`
justify-content: center;
width: 100%;
max-width: 442px;
height: auto;
padding: 30px;
`;
export const SponserDiv = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
`;
export const SponserMoney = styled.div`
margin-top: ${(props) => props.mt};
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
export const SponserComment = styled.div`
margin-top: ${(props) => props.mt};
display: flex;
flex-direction: column;
justify-content: center;
align-items: start;
`;
export const SponsorImg = styled.img`
width: 60px;
height: 60px;
border-radius: 100px;
margin-top: 10px;
`;
export const InputTag = styled.input`
width: 98%;
height: ${(props) => props.h};
background-color: #eae7de;
border-radius: 4px;
border: none;
margin-left: 10px;
margin-bottom: 10px;
padding-left: 10px;
padding-bottom: ${(props) => props.pb};
font-weight: 500;
font-size: 11px;
justify-content: start;
align-items: start;
`;
export const FundingNewline = styled.div`
width: 100%;
height: 12px;
`;
export const TogetherDiv = styled.div`
margin-top: 30px;
width: 442px;
height: 45px;
background-color: ${(props) => props.bc};
color: ${(props) => props.color};
`;
export const KakaoButton = styled.button`
justify-content: center;
align-items: center;
width: 100%;
height: 60px;
background-color: #fae101;
border-radius: 7px;
font-size: 19px;
font-weight: 600;
margin-top: 14px;
margin-bottom: ${(props) => props.mb};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
&:hover {
background-color: #fae102;
cursor: pointer;
}
`;
export const KakaoPayLogo = styled.img`
height: 35px;
margin-top: 5px;
`;
'Web_Project' 카테고리의 다른 글
전체 데스크탑뷰 적용 (0) | 2024.02.19 |
---|---|
데스크탑뷰 (0) | 2024.02.18 |
로그인모달창, 회원가입, 로그인 (1) | 2024.02.16 |
메인페이지 webkit-scrollbar 적용 (0) | 2024.02.16 |
카카오페이 API 연동 (0) | 2024.02.14 |