-
아마존 E-commerce 클론 -18) payment Button 만들기NODE.JS 2021. 5. 28. 13:17
먼저 샌드박스 계정을 만들고
sandbox로 앱을 create해준다.
이름입력 우리가 페이팔을 이용하기위해서는 client Id가 필요하다. .env파일에 안전하게 보관한다.
JWT_SECRET = somethingsecret PAYPAL_CLIENT_ID=AQ5wLOPTCxFTcWOJV43zenkyYO4C8E-e6U0E0znOHJuiysC7n4NB8QjkKJVgVC8ztpOfXupCKnISYBbc
server.js에 클라이언트키에 접근하는 API를 만들어준다.
app.get('/api/config/paypal', (req, res)=>{ res.send(process.env.PAYPAL_CLIENT_ID || 'sb') })
만약 라이브로 하고싶다면 live로 앱을 생성해서 클라이언트 아이디 넣어주면 된다.
이제 orderscreen.js로 가보자.
다음고 같이 추가하고 useEffect는 이처럼 변경해준다.
const orderId = props.match.params.id; const [sdkReady, setsdkReady] = useState(false) useEffect(() => { const addPayPalScript = async () =>{ const {data} = await axios.get('/api/config/paypal'); const script = document.createElement('script'); script.type = "text/javascript"; script.src = `http://www.paypal.com/sdk/js?client-id=${data}` script.async = true; script.onload = ()=>{ setsdkReady(true); }; document.body.appendChild(script); } if(!order._id){ dispatch(detailsOrder(orderId)); }else{ if(!order.isPaid){ if(!window.paypal){ addPayPalScript(); } }else{ setsdkReady(true); } } }, [dispatch, order, sdkReady, orderId])
이제 frontend에 페이팔 버튼을 설치한다.
npm install react-paypal-button-v2
이제 오더스크린에 버튼을 추가한다.
import {PaypalButton} from 'react-paypal-button-v2'; const successPaymentHandler = () =>{ } <li> <div className="row"> <div> <strong>Order Total</strong> </div> <div> <strong>${order.totalPrice.toFixed(2)}</strong> </div> </div> </li> { !order.isPaid &&( <li> {!sdkReady? (<LoadingBox></LoadingBox>): ( <PaypalButton amount={order.totalPrice} onSuccess = {successPaymentHandler}></PaypalButton> )} </li> ) } </ul>
여기서 orderDetailsReducer를 다음과 같이 order={}를제거해준다.
이는 우리가 디테일을 가져오기 전에 빈 객체로 만들어주면
또다시 orderscreen의 addpaypalscript의 useEffect가 작동하는데 이는 우리가 원한것이 아니기 때문이다.
export const orderDetailsReducer = (state = {loading:true}, action) =>{ switch(action.type){ case ORDER_DETAILS_REQUEST: return {loading:true} case ORDER_DETAILS_SUCCESS: return {loading:false, order:action.payload} case ORDER_DETAILS_FAIL: return {loading:false, error:action.payload} default: return state; } }
만약 라이브 계정이라면 결제가 진행될 것이다.
이제 주문이 진행되면 페이먼트가 완료된 창이 뜨도록 설정해두자.
order모델에 상세 정보를 추가하자.
paymentMethod:{ type:String, required:true }, paymentResult:{ id:String, Status:String, update_time:String, email_address:String }, item
라우터를 추가해준다.
orderRouter.put('/:id/pay', isAuth, expressAsyncHandler(async (req, res)=>{ const order = await Order.findById(req.params.id); if(order){ order.isPaid = true, order.paidAt = Date.now(); order.paymentResult = {id: req.body.id, status:req.body.status, update_time:req.body.update_time, email:req.body.email_address} const updatedOrder = await order.save(); res.send({message:'Order Paid', order: updatedOrder}) }else{ res.status(404).send({message:'Order Not Found'}) } }))
orderconstants추가한다.
export const ORDER_PAY_REQUEST='ORDER_PAY_REQUEST' export const ORDER_PAY_SUCCESS='ORDER_PAY_SUCCESS' export const ORDER_PAY_FAIL='ORDER_PAY_FAIL' export const ORDER_PAY_RESET= 'ORDER_PAY_RESET'
orderActions.js
export const payOrder = (order, paymentResult)=>(dispatch, getState)=>{ dispatch({ type:ORDER_PAY_REQUEST, payload:{order, paymentResult} }) const {userSignin:{userInfo}} = getState(); try{ const {data} = axios.put(`/api/orders/${order._id}/pay`, paymentResult,{ headers:{Authorization:`Bearer ${userInfo.token}`} }) dispatch({ type:ORDER_PAY_SUCCESS , payload:data }) }catch(error){ const message = error.response && error.response.data.message ? error.response.data.message : error.message; dispatch({ type:ORDER_PAY_FAIL, payload:message }) } }
orderReducers.js
export const orderPayReducer = (state={}, action)=>{ switch(action.type){ case ORDER_PAY_REQUEST: return {loading:true} case ORDER_PAY_SUCCESS: return {loading:false, success:true}; case ORDER_PAY_FAIL: return {loading:false, error:action.payload} default: return state; } }
store.js
const reducer = combineReducers({ productList: productListReducer, productDetails : productDetailsReducer, cart:cartReducer, userSignin: userSigninReducer, userRegister: userRegisterReducer, orderCreate:orderCreateReducer, orderDetails:orderDetailsReducer, orderPay: orderPayReducer })
orderScreen.js
만약에 주문이 존재하지 않거나, 이미 지불했거나, 주문이 존재하지만 주문아이디가 동일하지 않으면 주문상세페이지로 이동한다.
import { detailsOrder, payOrder } from '../actions/orderActions'; import axios from 'axios'; import {PayPalButton} from 'react-paypal-button-v2'; const orderPay = useSelector(state=>state.orderPay) const {loading:loadingPay, error:errorPay, success:successPay} = orderPay; useEffect(() => { const addPayPalScript = async () => { const { data } = await axios.get('/api/config/paypal'); const script = document.createElement('script'); script.type = 'text/javascript'; script.src = `https://www.paypal.com/sdk/js?client-id=${data}`; script.async = true; script.onload = () => { setSdkReady(true); }; document.body.appendChild(script); }; if ( !order || successPay || (order && order._id !== orderId) ) { dispatch(detailsOrder(orderId)); } else { if (!order.isPaid) { if (!window.paypal) { addPayPalScript(); } else { setSdkReady(true); } } } }, [dispatch, orderId, sdkReady, successPay, order]); const successPaymentHandler = (paymentResult) =>{ dispatch(payOrder(order, paymentResult)) } { !order.isPaid && ( <li> {!sdkReady? (<LoadingBox></LoadingBox>): ( <> { errorPay && <MessageBox variant='danger'>{errorPay}</MessageBox> } { loadingPay && <LoadingBox></LoadingBox> } <PayPalButton amount={order.totalPrice} onSuccess = {successPaymentHandler}></PayPalButton> </> )} </li> ) }
스타일을 주자.
.alert-success{ color:#20a020; background-color: #ffe0e0e0; }
추가로결제가 완료되면 페이지가 자꾸 새로고침 되는 것을 고치자.
reducers.에 추가한다.
case ORDER_PAY_RESET: return {}; default: return state; }
orderscreen에 추가
if ( !order || successPay || (order && order._id !== orderId) ) { dispatch({ type:ORDER_PAY_RESET }) dispatch(detailsOrder(orderId)); } else { if (!order.isPaid) { if (!window.paypal) { addPayPalScript(); } else { setSdkReady(true); } }
--------------
여기 페이팔 테스트가 실행이안된다. ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
'NODE.JS' 카테고리의 다른 글
아마존 E-commerce 클론 -20) UserProfile screen 만들고, Admin 미들웨어 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -19) Order History screen 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -17) order Screen 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -16) placeorder Screen 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -15) payment Screen 만들기 (0) 2021.05.28