-
아마존 E-commerce 클론 -22) Admin order관리페이지 만들기NODE.JS 2021. 5. 28. 21:57
이제 관리자가 들어온 주문을 볼 수 있는 페이지를 만들어보자.
먼저 모든주문을 조회하는 api를 만들자.
orderrouter.js
여기서 populate는 모든주문정보중에서 특정정보만을 가지고 오도록 지정하는것이다.
orderRouter.get('/', isAuth, isAdmin, expressAsyncHandler(async(req, res)=>{ const orders = await Order.find({}).populate('user', 'name'); res.send(orders); }))
이제 프론트엔드로와서 페이지를 만들어놓자.
OrderListScreen.js
import React, { useEffect } from 'react' import { useDispatch } from 'react-redux'; function OrderListScreen() { const dispatch = useDispatch(); useEffect(() => { dispatch(listOrders()); }, []) return ( <div> </div> ) } export default OrderListScreen
이제 리덕스를 사용할것이므로
orderConstants.js
export const ORDER_LIST_REQUEST = 'ORDER_LIST_REQUEST' export const ORDER_LIST_SUCCESS= 'ORDER_LIST_SUCCESS' export const ORDER_LIST_FAIL = 'ORDER_LIST_FAIL'
orderActions.js
export const listOrders = ()=> async(dispatch, getState) =>{ dispatch({ type:ORDER_LIST_REQUEST }) const {userSignin:{userInfo}} = getState(); try{ const {data} = await axios.get('/api/orders/', { headers:{Authorization:`Bearer ${userInfo.token}`} }) dispatch({ type:ORDER_LIST_SUCCESS, payload:data }) }catch(error){ const message = error.response && error.response.data.message ? error.response.data.message : error.message; dispatch({ type:ORDER_LIST_FAIL, payload: message }) } }
orderReducers.js
export const orderListReducer = (state={orders:[]}, action)=>{ switch(action.type){ case ORDER_LIST_REQUEST: return {loading:true} case ORDER_LIST_SUCCESS: return {loading:false, orders:action.payload} case ORDER_LIST_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, orderMineList:orderMineListReducer, userDetails:userDetailsReducer, userUpdateProfile:userUpdateProfileReducer, productCreate:productCreateReducer, productUpdate:productUpdateReducer, productDelete:productDeleteReducer, orderList:orderListReducer })
OrderListScreen.js
여기는 orderhistoryscreen과 매우 유사하기 때문에 복사해서 붙여넣기 해준다.
추가로 유저정보만 넣어준다.
추가로 delete버튼을 넣어준다.
import React, { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux'; import { listOrders } from '../actions/orderActions'; import LoadingBox from '../components/LoadingBox'; import MessageBox from '../components/MessageBox'; function OrderListScreen(props) { const orderList = useSelector(state => state.orderList) const {loading, error, orders} = orderList const dispatch = useDispatch(); useEffect(() => { dispatch(listOrders()); }, [dispatch]) const deleteHandler= (order)=>{ } return ( <div> <h1>Orders</h1> { loading? (<LoadingBox></LoadingBox>) : error? (<MessageBox variant= 'danger'>{error}</MessageBox>) : ( <table className="table"> <thead> <tr> <th>ID</th> <th>USER</th> <th>DATE</th> <th>TOTAL</th> <th>PAID</th> <th>DELIVERED</th> <th>ACTIONS</th> </tr> </thead> <tbody> {orders.map((order) => ( <tr key={order._id}> <td>{order._id}</td> <td>{order.user.name}</td> <td>{order.createdAt.substring(0, 10)}</td> <td>{order.totalPrice.toFixed(2)}</td> <td>{order.isPaid ? order.paidAt.substring(0, 10) : 'No'}</td> <td>{order.isDelivered? order.deliveredAt.substring(0,10): "No"}</td> <td> <button className="small" type="button" onClick={()=>{props.history.push(`/order/${order._id}`);}}>Details</button> <button className="small" type="button" onClick={()=>deleteHandler(order)}>Delete</button> </td> </tr> ))} </tbody> </table> ) } </div> ) } export default OrderListScreen
스크린을 app.js에 추가해준다.
import OrderListScreen from './screens/OrderListScreen'; <AdminRoute path="/orderlist" component={OrderListScreen} exact></AdminRoute>
잘 생성이 됐다. 디테일 버튼 누르면 디테일내용을 볼 수 있다. deleteHandler기능을 만들 것이다.
먼저 router(백엔드)에 기능을 추가해준다.
orderRouter.delete('/:id', isAuth, isAdmin, expressAsyncHandler(async(req, res)=>{ const order = await Order.findById(req.params.id); if(order){ const deleteOrder = await order.remove(); res.send({message:'Order Deleted', order:deleteOrder}) }else{ res.status(404).send({message:'Order Not Found'}) } }))
orderConstants.js
export const ORDER_DELETE_REQUEST = 'ORDER_DELETE_REQUEST' export const ORDER_DELETE_SUCCESS= 'ORDER_DELETE_SUCCESS' export const ORDER_DELETE_FAIL = 'ORDER_DELETE_FAIL' export const ORDER_DELETE_RESET = 'ORDER_DELETE_RESET'
orderActions.js
export const deleteOrder = (orderId)=> async(dispatch, getState) =>{ dispatch({ type:ORDER_DELETE_REQUEST, payload:orderId }) const {userSignin:{userInfo}} = getState(); try{ const {data} = await axios.delete(`/api/orders/${orderId}`, { headers:{Authorization:`Bearer ${userInfo.token}`} }) dispatch({ type:ORDER_DELETE_SUCCESS, payload:data }) }catch(error){ const message = error.response && error.response.data.message ? error.response.data.message : error.message; dispatch({ type:ORDER_DELETE_FAIL, payload: message }) } }
orderReducers.js
export const orderDeleteReducer = (state={}, action)=>{ switch(action.type){ case ORDER_DELETE_REQUEST: return {loading:true} case ORDER_DELETE_SUCCESS: return {loading:false, success:true} case ORDER_DELETE_FAIL: return {loading:false, error:action.payload} case ORDER_DELETE_RESET: return {}; default: return state; } }
store.js
const reducer = combineReducers({ productList: productListReducer, productDetails : productDetailsReducer, cart:cartReducer, userSignin: userSigninReducer, userRegister: userRegisterReducer, orderCreate:orderCreateReducer, orderDetails:orderDetailsReducer, orderPay: orderPayReducer, orderMineList:orderMineListReducer, userDetails:userDetailsReducer, userUpdateProfile:userUpdateProfileReducer, productCreate:productCreateReducer, productUpdate:productUpdateReducer, productDelete:productDeleteReducer, orderList:orderListReducer, orderDelete:orderDeleteReducer })
OrderListScreen.js
삭제가 완료되면 삭제된 주문이 저장되어있을 텐데, 페이지를 다시 리로딩하기전에 이를 리셋하도록 하자. (오더리스트 다시 가져오도록)
import { deleteOrder, listOrders } from '../actions/orderActions'; import { ORDER_DELETE_RESET } from '../constants/orderConstants'; function OrderListScreen(props) { const orderDelete = useSelector(state => state.orderDelete) const {loading:loadingDelete, error:errorDelete, success:successDelete} = orderDelete const dispatch = useDispatch(); useEffect(() => { dispatch({ type:ORDER_DELETE_RESET }) dispatch(listOrders()); }, [dispatch,successDelete]) const deleteHandler= (order)=>{ if(window.confirm('Are you sure to delete?')){ dispatch(deleteOrder(order._id)); } } return ( <div> <h1>Orders</h1> {loadingDelete && <LoadingBox></LoadingBox>} {loadingDelete && <MessageBox variant='danger'>{errorDelete}</MessageBox>}
정상적으로 삭제된다. 이제 delivery를 가능하게끔 만들자.
상품 디테일 페이지에 들어가면 상품배송을 시작하는 버튼을 만들 것이다.
먼저 orderRouter를 만들 것인데,
pay라우터와 매우 비슷하기 때문에 복사해서 수정한다.
orderRouter.put('/:id/deliver', isAuth,isAdmin, expressAsyncHandler(async (req, res)=>{ const order = await Order.findById(req.params.id); if(order){ order.isDelivered = true, order.deliveredAt = Date.now(); const updatedOrder = await order.save(); res.send({message:'Order Delivered', order: updatedOrder}) }else{ res.status(404).send({message:'Order Not Found'}) } }))
orderScreen.js에서 맨 마직막에 사용자가 관리자라면 볼 수 있는 배달버튼을 만들도록 하자.
const userSignin = useSelector(state => state.userSignin) const {userInfo} = userSignin const deliverHandler = () =>{ dispatch(deliverOrder()); } { !order.isPaid && ( <li> {!sdkReady? (<LoadingBox></LoadingBox>): ( <> { errorPay && <MessageBox variant='danger'>{errorPay}</MessageBox> } { loadingPay && <LoadingBox></LoadingBox> } <PayPalButton amount={order.totalPrice} onSuccess = {successPaymentHandler}></PayPalButton> </> )} </li> ) } {userInfo.isAdmin && order.isPaid && !order.isDelivered &&( <li> <button type="button" className="primary block" onClick={deliverHandler}> Deliver Order </button> </li> )}
orderConstants.js
export const ORDER_DELIVER_REQUEST='ORDER_DELIVER_REQUEST' export const ORDER_DELIVER_SUCCESS='ORDER_DELIVER_SUCCESS' export const ORDER_DELIVER_FAIL='ORDER_DELIVER_FAIL' export const ORDER_DELIVER_RESET= 'ORDER_DELIVER_RESET'
orderActions.js
payorder를 복사해서 수정해준다. (매우비슷)
export const deliverOrder = (orderId)=>async(dispatch, getState)=>{ dispatch({ type:ORDER_DELIVER_REQUEST, payload:orderId }) const {userSignin:{userInfo}} = getState(); try{ const {data} = axios.put(`/api/orders/${orderId}/deliver`,{},{ headers:{Authorization:`Bearer ${userInfo.token}`} }) dispatch({ type:ORDER_DELIVER_SUCCESS , payload:data }) }catch(error){ const message = error.response && error.response.data.message ? error.response.data.message : error.message; dispatch({ type:ORDER_DELIVER_FAIL, payload:message }) } }
orderReducers.js
export const deliverOrderReducer = (state={}, action)=>{ switch(action.type){ case ORDER_DELIVER_REQUEST: return {loading:true} case ORDER_DELIVER_SUCCESS: return {loading:false, success:true}; case ORDER_DELIVER_FAIL: return {loading:false, error:action.payload} case ORDER_DELIVER_RESET: return {}; default: return state; } }
store.js
const reducer = combineReducers({ productList: productListReducer, productDetails : productDetailsReducer, cart:cartReducer, userSignin: userSigninReducer, userRegister: userRegisterReducer, orderCreate:orderCreateReducer, orderDetails:orderDetailsReducer, orderPay: orderPayReducer, orderMineList:orderMineListReducer, userDetails:userDetailsReducer, userUpdateProfile:userUpdateProfileReducer, productCreate:productCreateReducer, productUpdate:productUpdateReducer, productDelete:productDeleteReducer, orderList:orderListReducer, orderDelete:orderDeleteReducer, orderDeliver:orderDeliverReducer })
OrderScreen.js
import { ORDER_DELIVER_RESET, ORDER_PAY_RESET } from '../constants/orderConstants'; const userSignin = useSelector(state => state.userSignin) const {userInfo} = userSignin const orderDeliver = useSelector(state => state.orderDeliver) const {loading:loadingDeliver, error:errorDeliver, success:successDeliver} = orderDeliver 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 || successDeliver|| (order && order._id !== orderId) ) { dispatch({ type:ORDER_PAY_RESET }) dispatch({ type:ORDER_DELIVER_RESET }) dispatch(detailsOrder(orderId)); } else { if (!order.isPaid) { if (!window.paypal) { addPayPalScript(); } else { setSdkReady(true); } } } }, [dispatch, orderId, sdkReady, successPay, order, successDeliver]); const deliverHandler = () =>{ dispatch(deliverOrder(order._id)); } {userInfo.isAdmin && order.isPaid && !order.isDelivered &&( <li> {loadingDeliver && <LoadingBox></LoadingBox>} {errorDeliver && <MessageBox variant='danger'>{errorDeliver}</MessageBox>} <button type="button" className="primary block" onClick={deliverHandler}> Deliver Order </button> </li> )} </ul> </div> </div> </div> </div>
결제가 안되서 딜리버 실습도 못하고 있다 ㅠㅠㅠㅠㅠㅠ 이부분 꼭 나중에 체크하기!!!!
(일단 &&ispaid 부분을 삭제하고 실습해봄)
'NODE.JS' 카테고리의 다른 글
아마존 E-commerce 클론 -24) Seller 페이지 만들기 (Product, Order) (0) 2021.05.29 아마존 E-commerce 클론 -23) Admin user관리페이지 만들기 (0) 2021.05.29 아마존 E-commerce 클론 -21) Admin product관리페이지 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -20) UserProfile screen 만들고, Admin 미들웨어 만들기 (0) 2021.05.28 아마존 E-commerce 클론 -19) Order History screen 만들기 (0) 2021.05.28