import React from 'react';
import { useNavigate } from 'react-router-dom';
import {
MainContainer,
LeftContainer,
Logo,
P,
Button,
RightContainer,
Navbar,
NavbarBtn,
SponserMoney,
InputTag,
Body,
FundingDiv,
SponserDiv,
SponserComment,
SponsorImg,
TogetherDiv,
} from './FundingPayStyles';
import CheckBox from '../FundingPay/CheckBox/CheckBox';
import KakaoPay from './KakaoPay/KakaoPay';
const FundingPay = () => {
const navigate = useNavigate();
const meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
document.getElementsByTagName('head')[0].appendChild(meta);
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="white" bc="orange">
펀딩 시작하기
</Button>
</LeftContainer>
<RightContainer>
<Navbar>
<NavbarBtn onClick={() => navigate('/fundingdetail')} fs="15px" fw="800" pl="15px">
😉 펀딩 상세페이지로 이동
</NavbarBtn>
</Navbar>
<Body>
<FundingDiv>
<SponserMoney>
<SponsorImg src="/imgs/junjihyun.jpg" alt="logo" />
<P pt="10px" fs="16px" fw="800" pb="5px">
윤다인 님에게
</P>
<P fs="16px" fw="800" pb="5px">
5,000원
</P>
<P fs="16px" fw="800">
후원하기
</P>
</SponserMoney>
<P pt="20px" pb="20px" fs="16px" fw="900">
후원자
</P>
<SponserDiv>
<SponserComment mt="10px">
<P pl="10px" pb="5px" fs="13px" fw="800">
이름
</P>
<InputTag type="text" placeholder="남길 이름을 입력해주세요" h="40px" />
<P pl="10px" fs="10px" fw="800">
주최자에게 이름이 모두 공개되고, 후원자 목록에는 두번째 글자부터 *으로 표시됩니다.
예) 김 * *
</P>
</SponserComment>
</SponserDiv>
<P pt="10px" pl="10px" pb="5px" fs="13px" fw="800">
메시지
</P>
<InputTag type="text" placeholder="남길 메시지를 입력해주세요" pb="50px" h="100px" />
<P pl="10px" fs="10px" fw="800">
현재는 테스트 기간으로, 실제 결제가 이루어지지 않습니다. 대신 1명이 참여할 때마다 개설자에게
1,000원이 적립됩니다.
</P>
</FundingDiv>
<CheckBox />
<TogetherDiv pt="10px" bc="orange">
<P pl="140px" fs="14px" fw="800">
<br />
지금 선물하면 3등이에요!
<br />
</P>
</TogetherDiv>
<KakaoPay />
</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;
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};
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;
height: 100vh;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
@media (max-width: 442px) {
width: 100%;
}
`;
// 네브바 영역
export const Navbar = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 70px;
`;
export const NavbarBtn = styled.button`
font-size: ${(props) => props.fs};
font-weight: ${(props) => props.fw};
padding-left: ${(props) => props.pl};
padding-right: ${(props) => props.pr};
`;
// 바디 영역
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};
`;
import React, { useEffect } from 'react'; // React와 useEffect 훅을 React 라이브러리에서 불러옵니다.
import axios from 'axios'; // HTTP 요청을 보내기 위해 axios를 가져옵니다.
import {
Button,
KakaoPayLogo,
} from './KakaoPayStyles';
const KakaoPay = () => {
// KakaoPay라는 함수형 컴포넌트를 정의합니다.
const sendAmountToServer = async (amount) => {
// 서버로 금액을 전송하는 비동기 함수를 정의합니다.
const accessToken = localStorage.getItem('accessToken'); // localStorage에서 accessToken을 가져옵니다.
try {
const response = await axios.post(
'http://localhost:8081/api/point',
{
// 서버로 POST 요청을 보냅니다.
point: amount, // 요청 본문에 금액을 담습니다.
},
{
headers: {
Authorization: accessToken, // 요청 헤더에 accessToken을 포함시킵니다.
},
}
);
if (response.status === 200) {
// 요청이 성공했는지 확인합니다.
alert('서버로 amount 전송 완료'); // 서버로의 전송이 성공한 경우 알림창을 띄웁니다.
} else {
alert('서버로 amount 전송 실패'); // 서버로의 전송이 실패한 경우 알림창을 띄웁니다.
}
} catch (error) {
console.error('서버로 amount 전송 중 오류:', error); // 전송 중 오류가 발생한 경우 콘솔에 오류를 기록합니다.
alert('서버로 amount 전송 중 오류 발생'); // 전송 중 오류가 발생한 경우 알림창을 띄웁니다.
}
};
const requestPay = () => {
// 결제 요청을 처리하는 함수를 정의합니다.
const { IMP } = window; // window 객체에서 IMP 객체를 가져옵니다.
IMP.init('imp82385247'); // IMP 객체를 초기화합니다.
IMP.request_pay(
{
// IMP 객체를 사용하여 결제 요청을 보냅니다.
pg: 'kakaopay.TC0ONETIME', // 결제 수단을 설정합니다.
pay_method: 'card', // 결제 방법을 설정합니다.
merchant_uid: new Date().getTime(), // 고유한 상점 ID를 생성합니다.
name: 'Giftipie후원금', // 상품 이름을 설정합니다.
amount: 10000, // 결제 금액을 설정합니다.
buyer_email: 'test@naver.com', // 구매자 이메일을 설정합니다.
buyer_name: '코드쿡', // 구매자 이름을 설정합니다.
buyer_tel: '010-1234-5678', // 구매자 전화번호를 설정합니다.
// buyer_addr: '서울특별시', // 구매자 주소를 설정합니다.
// buyer_postcode: '123-456', // 구매자 우편번호를 설정합니다.
},
async (rsp) => {
// 결제 요청 후 콜백 함수를 처리합니다.
try {
const { data } = await axios.post('http://localhost:8081/verifyIamport/' + rsp.imp_uid); // 서버에서 결제 검증을 수행합니다.
if (rsp.paid_amount === data.response.amount) {
// 결제 금액이 서버 응답과 일치하는지 확인합니다.
alert('결제 성공'); // 결제가 성공한 경우 알림창을 띄웁니다.
sendAmountToServer(rsp.paid_amount); // 결제된 금액을 서버로 전송합니다.
} else {
alert('결제 실패'); // 결제가 실패한 경우 알림창을 띄웁니다.
}
} catch (error) {
console.error('결제 검증 중 오류:', error); // 결제 검증 중 오류가 발생한 경우 콘솔에 오류를 기록합니다.
alert('결제 실패'); // 결제 검증 중 오류가 발생한 경우 알림창을 띄웁니다.
}
}
);
};
useEffect(() => {
// 외부 스크립트를 로드하기 위해 useEffect 훅을 사용합니다.
const jquery = document.createElement('script'); // jQuery 스크립트 엘리먼트를 생성합니다.
jquery.src = 'http://code.jquery.com/jquery-1.12.4.min.js'; // jQuery 스크립트의 소스를 설정합니다.
const iamport = document.createElement('script'); // Iamport 스크립트 엘리먼트를 생성합니다.
iamport.src = 'http://cdn.iamport.kr/js/iamport.payment-1.1.7.js'; // Iamport 스크립트의 소스를 설정합니다.
document.head.appendChild(jquery); // jQuery 스크립트를 문서 헤드에 추가합니다.
document.head.appendChild(iamport); // Iamport 스크립트를 문서 헤드에 추가합니다.
return () => {
// 컴포넌트가 언마운트될 때 추가한 스크립트를 제거하기 위한 클린업 함수를 반환합니다.
document.head.removeChild(jquery); // 문서 헤드에서 jQuery 스크립트를 제거합니다.
document.head.removeChild(iamport); // 문서 헤드에서 Iamport 스크립트를 제거합니다.
};
}, []); // useEffect가 초기 렌더링 후 한 번만 실행되도록 빈 의존성 배열을 전달합니다.
return (
<div>
{/* <button onClick={requestPay}>결제하기</button> */}
<Button onClick={requestPay}>
<KakaoPayLogo src="/imgs/kakaopay.png" alt="image" />
</Button>
</div>
);
};
export default KakaoPay; // Payment 컴포넌트를 내보냅니다.
import styled from "styled-components";
export const Button = 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: ${(props) => props.mt};
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;
`
import React, { useState, useEffect } from 'react';
import {
CheckBoxDiv,
Checkbox,
FontSize5,
} from './CheckBoxStyles';
function CheckBox() {
const [allCheck, setAllCheck] = useState(false);
const [ageCheck, setAgeCheck] = useState(false);
const [useCheck, setUseCheck] = useState(false);
const [infoCheck, setInfoCheck] = useState(false);
const [marketingCheck, setMarketingCheck] = useState(false);
const allBtnEvent = () => {
if (allCheck === false) {
setAllCheck(true);
setAgeCheck(true);
setUseCheck(true);
setInfoCheck(true);
setMarketingCheck(true);
} else {
setAllCheck(false);
setAgeCheck(false);
setUseCheck(false);
setInfoCheck(false);
setMarketingCheck(false);
}
};
const ageBtnEvent = () => {
if (ageCheck === false) {
setAgeCheck(true);
} else {
setAgeCheck(false);
}
};
const useBtnEvent = () => {
if (useCheck === false) {
setUseCheck(true);
} else {
setUseCheck(false);
}
};
const infoBtnEvent = () => {
if (useCheck === false) {
setInfoCheck(true);
} else {
setInfoCheck(false);
}
};
const marketingBtnEvent = () => {
if (marketingCheck === false) {
setMarketingCheck(true);
} else {
setMarketingCheck(false);
}
};
useEffect(() => {
if (ageCheck === true && useCheck === true && infoCheck === true && marketingCheck === true) {
setAllCheck(true);
} else {
setAllCheck(false);
}
}, [ageCheck, useCheck, infoCheck, marketingCheck]);
return (
<div>
<CheckBoxDiv>
<Checkbox type="checkbox" id="all-check" checked={allCheck} onChange={allBtnEvent} />
<FontSize5>모두 동의합니다</FontSize5>
</CheckBoxDiv>
<CheckBoxDiv>
<Checkbox type="checkbox" id="check1" checked={ageCheck} onChange={ageBtnEvent} />
<FontSize5>만 14세 이상 가입 동의 (필수)</FontSize5>
</CheckBoxDiv>
<CheckBoxDiv>
<Checkbox type="checkbox" id="check2" checked={useCheck} onChange={useBtnEvent} />
<FontSize5>이용약관 동의 (필수)</FontSize5>
</CheckBoxDiv>
<CheckBoxDiv>
<Checkbox type="checkbox" id="check3" checked={infoCheck} onChange={infoBtnEvent} />
<FontSize5>개인정보 수집/이용 동의 (필수)</FontSize5>
</CheckBoxDiv>
<CheckBoxDiv>
<Checkbox type="checkbox" id="check4" checked={marketingCheck} onChange={marketingBtnEvent}/>
<FontSize5>마케팅 정보 수신 동의 (선택)</FontSize5>
</CheckBoxDiv>
</div>
);
}
export default CheckBox;
import styled from "styled-components";
export const CheckBoxDiv = styled.div`
display: flex;
flex-direction: row;
align-items: center;
height: 21px;
`;
export const Checkbox = styled.input`
margin-right: 10px;
margin-left: 45px;
width: 12px;
height: 12px;
accent-color: black;
`;
export const FontSize5 = styled.h5`
font-size: 10px;
font-weight: 500;
`;
'React' 카테고리의 다른 글
모달창 Url 입력 -> 이미지 출력 (0) | 2024.02.09 |
---|---|
api post, get, patch 기능 구현 (1) | 2024.02.06 |
[주특기 프로젝트] FE & BE : 첫 협업 (0) | 2024.01.21 |
[비동기통신 axios.get 요청] json-server API 명세서 확인 (0) | 2024.01.11 |
React Router로 SPA 개발하기 (0) | 2024.01.10 |