본문 바로가기

React

[Project] 나이스 페이먼츠 테스트용 전자결제 연동하기 (4) - 프론트엔드 폼 구현 2차

단순히 고정값을 보내어 호출한 저번 포스팅에 이어,

이번 포스팅에서는 폼에서 수정한 값으로 결제창 호출 시 데이터를 보낼 수 있도록 구현하겠습니다.

 

 

 

1. "가격", "결제 수단", "구매수량에 따른 최종 결제 금액"의 상태값이 변할 수 있도록 useState를 활용하여 변수를 선언해 줍니다.

  const [price, setPrice] = useState<number>(1004);
  const [selctedMethod, setSelectedMethod] = useState<string>('');
  const [totalPrice, setTotalPrice] = useState<number>(1004);

 

2. 폼 제출 시 결제 수단의 선택 유무를 판단하여 나이스페이 결제창을 호출하는 함수를 구현합니다.

  const handleSubmit = (e: any) => {
    e.preventDefault();
    if (e.target.method.value === '') {
      alert('결제수단을 선택하세요.')
      return false;
    } else {
      getPayments();
    }
  }

 

3. react + typescript + styled-components를 사용하여 작성한 최종 코드입니다.

import axios from 'axios';
import React, { useState } from 'react';
import { Tomato } from './assets/index';
import { styled } from 'styled-components';

interface ErrorResultType {
  errorMsg: string;
}

const App = () => {
  const [name, setName] = useState<string>("맛있는 방울토마토");
  const [price, setPrice] = useState<number>(1004);
  const [selctedMethod, setSelectedMethod] = useState<string>('');
  const [totalPrice, setTotalPrice] = useState<number>(1004);

  // 나이스 페이 결제창 호출
  const getPayments = async () => {
    try {
        const res = await axios.get(`http://localhost:8000/api/payments`);
        const { AUTHNICE } = window as any;
      
        AUTHNICE.requestPay({
          clientId: res.data.clientId,
          method: selctedMethod,
          orderId: res.data.orderId,
          amount: totalPrice,
          goodsName: name,
          returnUrl: '/api/paysuccess',
          fnError: function (result: ErrorResultType) {
            console.log('개발자확인용 : ' + result.errorMsg);
          }
        });
    } catch (error) {
        console.log(error);
    }
  }

  // 폼 제출
  const handleSubmit = (e: any) => {
    e.preventDefault();
    if (e.target.method.value === '') {
      alert('결제수단을 선택하세요.')
      return false;
    } else {
      getPayments();
    }
  }
  return (
    <AppContainer>
      <ProductImage src={Tomato} alt=''></ProductImage>
      <FormContainer 
        onSubmit={(e:any) => handleSubmit(e)}>
        <FormBox>
          <h4>상품명</h4>
          <p>{name}</p>
        </FormBox>
        <FormBox>
          <h4>결제 수단</h4>
          <MethodContainer>
            <MethodBox>
              <label htmlFor='card'>카드</label>
              <input id='card' name='method' type='radio' value={'card'}
                onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
            <MethodBox>
              <label htmlFor='bank'>계좌이체</label>
              <input id='bank' name='method' type='radio' value={'bank'}
                onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
            <MethodBox>
              <label htmlFor='cellphone'>휴대폰</label>
              <input id='cellphone' name='method' type='radio' value={'cellphone'}
              onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
            <MethodBox>
              <label htmlFor='kakaopay'>카카오페이</label>
              <input id='kakaopay' name='method' type='radio' value={'kakaopay'}
              onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
            <MethodBox>
              <label htmlFor='samsungpayCard'>삼성페이</label>
              <input id='samsungpayCard' name='method' type='radio' value={'samsungpayCard'} onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
            <MethodBox>
              <label htmlFor='naverpayCard'>네이버페이</label>
              <input id='naverpayCard' name='method' type='radio' value={'naverpayCard'}
              onChange={(e) => setSelectedMethod(e.target.value)}></input>
            </MethodBox>
          </MethodContainer>
        </FormBox>
        <FormBox>
          <h4>수량</h4>
          <input
            className='count-input'
            type='number'
            min={1}
            defaultValue={1}
            onChange={(e) => {
              const value = Number(e.target.value);
              setTotalPrice(value * price);
            }}></input>
        </FormBox>
        <FormBox>
          <h4>결제 금액</h4>
          <p>{totalPrice}원</p>
        </FormBox>
        <BuyButton>구매하기</BuyButton>
      </FormContainer>
    </AppContainer>
  );
}

export default App;

const AppContainer = styled.div`
  padding: 100px;
`;
const FormBox = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 14px;
  .count-input {
    width: 100px;
  }
`;
const MethodContainer = styled.div`
  display: flex;
`;
const MethodBox = styled.div`
  display: flex;
  margin-right: 15px;
  input {
    margin-left: 5px;
  }
`;
const ProductImage = styled.img`
  width: 400px;
  height: 300px;
`;
const FormContainer = styled.form`
  margin-top: 20px;
`;
const BuyButton = styled.button`
  width: 70px;
  height: 30px;
  background-color: black;
  color: white;
  font-size: 15px;
`;

 

4. 시연 영상