ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아마존 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 부분을 삭제하고 실습해봄)

     

     

     

     

     

     

     

     

     

Designed by Tistory.