-
아마존 E-commerce 클론 -26) Top Seller Carousel 추가하고, 장바구니 설정하기(동일 주문자의 상품만 장바구니에 추가가능)NODE.JS 2021. 5. 29. 22:05
홈스크린에 topseller들을 보여주는 carousel을 추가할 것이다.
frontent 에 react carousel을 추가하자
npm install react-responsive-carousel
홈스크린에 carousel을 넣어주자.
import {Carousel} from 'react-responsive-carousel'; import 'react-responsive-carousel/lib/styles/carousel.min.css'
useRouter로 가서 탑셀러들을 보여주는 라우트를 생성한다.
내림차순으로 정렬하고 그중에서 탑3만 가지고 온다.
userRouter.get('/top-sellers', expressAsyncHandler(async(req, res)=>{ const topSellers = await User.find({isSeller:true}).sort({'seller.rating':-1}).limit(3) res.send(topSellers) }))
이제 userConstants.js
export const USER_TOPSELLERS_LIST_REQUEST = 'USER_TOPSELLERS_LIST_REQUEST' export const USER_TOPSELLERS_LIST_SUCCESS = 'USER_TOPSELLERS_LIST_SUCCESS' export const USER_TOPSELLERS_LIST_FAIL = 'USER_TOPSELLERS_LIST_FAIL'
userActions.js
유저리스트를 가져오는 액션과 매우비슷하기 때문에 복사해서 일부수정해준다.
export const listTopSellers = () =>async(dispatch)=>{ dispatch({ type: USER_TOPSELLERS_LIST_REQUEST }) try{ const {data} = await axios.get(`/api/users/top-sellers`) dispatch({ type: USER_TOPSELLERS_LIST_SUCCESS, payload:data }) }catch(error){ const message = error.response && error.response.data.message ? error.response.data.message : error.message dispatch({ type: USER_TOPSELLERS_LIST_FAIL, payload:message }) } }
userReducers.js
export const userTopSellerListReducer = (state = {loading:true} ,action)=>{ switch(action.type){ case USER_TOPSELLERS_LIST_REQUEST: return {loading:true} case USER_TOPSELLERS_LIST_SUCCESS: return {loading:false, users:action.payload} case USER_TOPSELLERS_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, orderDelete:orderDeleteReducer, orderDeliver:orderDeliverReducer, userList:userListReducer, userDelete:userDeleteReducer, userUpdate:userUpdateReducer, userTopSellerList:userTopSellerListReducer })
HomeScreen.js
import {Carousel} from 'react-responsive-carousel'; import 'react-responsive-carousel/lib/styles/carousel.min.css' import { listTopSellers } from '../actions/userActions'; function HomeScreen() { const dispatch = useDispatch(); const userTopSellersList = useSelector(state => state.userTopSellersList) const{loading:loadingSellers, error:errorSellers, users:sellers} = userTopSellersList useEffect(() => { dispatch(listProducts({})); dispatch(listTopSellers()); }, [dispatch]) return ( <div> <h2>Top Sellers</h2> {loadingSellers ?( <LoadingBox></LoadingBox> ): errorSellers?( <MessageBox variant="danger">{errorSellers}</MessageBox> ): ( <> {sellers.length===0 && <MessageBox>No Seller Found</MessageBox>} </> )} <h2>Featured Products</h2> {loading ?( <LoadingBox></LoadingBox> ): error?( <MessageBox variant="danger">{error}</MessageBox> ): ( <> {products.length===0 && <MessageBox>No Product Found</MessageBox>} <div className="row center"> {products.map(product=>( <Product key={product._id} product = {product}/> ))} </div> </> )} </div> ) } export default HomeScreen
이제 carousel을 이용해보자.
<h2>Top Sellers</h2> {loadingSellers ?( <LoadingBox></LoadingBox> ): errorSellers?( <MessageBox variant="danger">{errorSellers}</MessageBox> ): ( <> {sellers.length===0 && <MessageBox>No Seller Found</MessageBox>} <Carousel showArrows autoPlay showThumbs={false}> {sellers.map((seller)=>( <div key={seller._id}> <Link to = {`/seller/${seller._id}`}> <img src={seller.seller.logo} alt={seller.seller.name} /> <p className="legend">{seller.seller.name}</p> </Link> </div> ))} </Carousel> </> )}
스타일링을 주자
/* Carousel */ .carousel .slide img{ max-width: 30rem; }
이제 장바구니에 동일 판매자의 제품만 넣을 수 있도록 설정하자.
constants추가하자.
export const CART_ADD_ITEM_FAIL = 'CART_ADD_ITEM_FAIL'
cartActions을 수정하자. (카트아이템이 있는데, 추가하려는 상품과 이미 있는 상품의 판매자가 다르면 추가할 수 없다)
export const addToCart = (productId, qty)=> async(dispatch, getState)=>{ const {data} =await Axios.get(`/api/products/${productId}`); const {cart:{cartItems}} = getState(); if(cartItems.length>0 && data.seller._id !==cartItems[0].seller._id){ dispatch({ type:CART_ADD_ITEM_FAIL, payload:"Can't Add To Cart. Buy from one seller at a time." }) } dispatch({ type:CART_ADD_ITEM, payload:{ name:data.name, image:data.image, price:data.price, countInStock:data.countInStock, product:data._id, seller:data.seller, qty, } }); localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems)); }
cartreducers.추가하고
removeitem과 cartempty에는 error:'' 으로 추가해주는데 그 이유는 error가 카트스크린에 영향을 미칠 수도 있기 때문이다.
export const cartReducer = (state={cartItems:[]}, action)=>{ switch(action.type){ case CART_ADD_ITEM: const item = action.payload; const existItem = state.cartItems.find(x=>x.product===item.product) if(existItem){ return { ...state, cartItems:state.cartItems.map(x=>x.product===existItem.product? item:x) } }else{ return {...state, cartItems:[...state.cartItems, item]}; } case CART_ADD_ITEM_FAIL: return {...state, error:action.payload} case CART_REMOVE_ITEM: return {...state, error:'', cartItems:state.cartItems.filter(x=>x.product!==action.payload)}; case CART_SAVE_SHIPPING_ADDRESS: return {...state,shippingAddress:action.payload } case CART_SAVE_PAYMENT_METHOD: return {...state, paymentMethod:action.payload} case CART_EMPTY: return {...state,error:'', cartItems:[]} default: return state; } }
카트 스크린으로 가보자.
위에서 action에 에러를 추가했으니 만약 에러가 발생한다면, 처리하는 곳을 넣어준다. (메세지 나타내기)
const cart = useSelector(state=>state.cart); const {cartItems, error} = cart; <div className="row top"> <div className="col-2"> <h1>Shopping Cart</h1> {error && <MessageBox variant='danger'>{error}</MessageBox>} {cartItems.length ===0? (<MessageBox> Cart is Empty. <Link to ="/">Go Shopping</Link> </MessageBox>
상품 추가가 안되게 막아보자.
cartActions
export const addToCart = (productId, qty)=> async(dispatch, getState)=>{ const {data} =await Axios.get(`/api/products/${productId}`); const {cart:{cartItems}} = getState(); if(cartItems.length>0 && data.seller._id !==cartItems[0].seller._id){ dispatch({ type:CART_ADD_ITEM_FAIL, payload:"Can't Add To Cart. Buy from one seller at a time." }) }else{ dispatch({ type:CART_ADD_ITEM, payload:{ name:data.name, image:data.image, price:data.price, countInStock:data.countInStock, product:data._id, seller:data.seller, qty, } }); localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems)); } }
보이는 문구를 조금 바꿔보자.
export const addToCart = (productId, qty)=> async(dispatch, getState)=>{ const {data} =await Axios.get(`/api/products/${productId}`); const {cart:{cartItems}} = getState(); if(cartItems.length>0 && data.seller._id !==cartItems[0].seller._id){ dispatch({ type:CART_ADD_ITEM_FAIL, payload:`Can't Add To Cart. Buy only from ${cartItems[0].seller.seller.name} in this order.` })
여기서 카트를 새로 고침해서 들어가도 저 에러메세지가 사라지지 않는데 그 이슈를 고쳐보자.
cartReducer의 나머지 항목에서 error:''를 추가해준다.
export const cartReducer = (state={cartItems:[]}, action)=>{ switch(action.type){ case CART_ADD_ITEM: const item = action.payload; const existItem = state.cartItems.find(x=>x.product===item.product) if(existItem){ return { ...state, error:'', cartItems:state.cartItems.map(x=>x.product===existItem.product? item:x) } }else{ return {...state, error:'',cartItems:[...state.cartItems, item]}; } case CART_ADD_ITEM_FAIL: return {...state, error:action.payload} case CART_REMOVE_ITEM: return {...state, error:'', cartItems:state.cartItems.filter(x=>x.product!==action.payload)}; case CART_SAVE_SHIPPING_ADDRESS: return {...state,shippingAddress:action.payload } case CART_SAVE_PAYMENT_METHOD: return {...state, paymentMethod:action.payload} case CART_EMPTY: return {...state,error:'', cartItems:[]} default: return state; } }
'NODE.JS' 카테고리의 다른 글
아마존 E-commerce 클론 -28) Rate & Review 생성하기 (0) 2021.05.30 아마존 E-commerce 클론 -27) Search Box ,Search Filter기능 , Side bar, sort & Filter 만들기 (0) 2021.05.29 아마존 E-commerce 클론 -25) Seller 정보페이지 만들기 (0) 2021.05.29 아마존 E-commerce 클론 -24) Seller 페이지 만들기 (Product, Order) (0) 2021.05.29 아마존 E-commerce 클론 -23) Admin user관리페이지 만들기 (0) 2021.05.29