diff --git a/src/api/cartAPI.ts b/src/api/cartAPI.ts new file mode 100644 index 0000000..192eabb --- /dev/null +++ b/src/api/cartAPI.ts @@ -0,0 +1,13 @@ +import axios from 'axios'; + +axios.defaults.withCredentials = true; + +export const CartfetchProducts = async () => { + try { + const response = await axios.get('/api/v1/user/cart'); + return response.data; + } catch (error) { + console.error('Error fetching products:', error); + throw error; + } +}; \ No newline at end of file diff --git a/src/pages/MyBagPage.tsx b/src/pages/MyBagPage.tsx index 5431cb8..0ff315d 100644 --- a/src/pages/MyBagPage.tsx +++ b/src/pages/MyBagPage.tsx @@ -1,57 +1,65 @@ -import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; +import React, { useEffect, useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { RootState } from '../store/store'; -import { setProducts, increaseQuantity, decreaseQuantity, removeProduct } from '../store/cartSlice'; -import { ProductInterface } from '../models/product'; -import { PayloadAction, createAction } from '@reduxjs/toolkit'; -// import ProductOption from '../components/ProductOption/ProductOption'; +import { decreaseQuantity, increaseQuantity, removeProduct, fetchCartProducts } from '../store/cartSlice'; +// import { ProductInterface } from '../models/product'; // 장바구니에 상품 추가 액션 생성 -export const addToCart = createAction('cart/add'); +// export const addToCart = createAction('cart/add'); // 나의 장바구니 페이지 컴포넌트 const MyBagPage: React.FC = () => { const navigate = useNavigate(); const dispatch = useDispatch(); - const products = useSelector((state: RootState) => state.cart.products); + const products = useSelector((state: RootState) => state.cart.products); + const cartStatus = useSelector((state: RootState) => state.cart.status); + // const cartError = useSelector((state: RootState) => state.cart.error); - // 감소 함수 - const handleDecreaseQuantity = useCallback( - (index: number) => { - dispatch(decreaseQuantity(index)); - }, - [dispatch] - ); - // 증가 함수 - const handleIncreaseQuantity = useCallback( - (index: number) => { - dispatch(increaseQuantity(index)); - }, - [dispatch] - ); + useEffect(() => { + if (cartStatus === 'idle') { + dispatch(fetchCartProducts()); + } + }, [dispatch, cartStatus]); - // 삭제 함수 - const handleRemoveProduct = useCallback( - (index: number) => { - dispatch(removeProduct(index)); + + const handleDecreaseQuantity = useCallback( + (index: React.Key | null | undefined) => { + if (typeof index === "number") { + dispatch(decreaseQuantity(index)); + } }, [dispatch] - ); - - // 총 가격 계산 - const totalPrice = useMemo(() => { - return products.reduce((total: number, product: { price: any; quantity: any }) => { - return total + (Number(product.price) || 1) * (Number(product.quantity) || 1); - }, 0); - }, [products]); - - // 이전 페이지로 돌아가는 함수 - const goBackToPreviousPage = () => { - navigate(-2); - }; + ); + + const handleIncreaseQuantity = useCallback( + (index: number) => { + dispatch(increaseQuantity(index)); + }, + [dispatch] + ); + + const handleRemoveProduct = useCallback( + (index: number) => { + dispatch(removeProduct(index)); + }, + [dispatch] + ); + + const totalPrice = useMemo(() => { + return products.reduce((total: number, product: { price: any; quantity: any; }) => { + return total + (Number(product.price) || 1) * (Number(product.quantity) || 1); + }, 0); + }, [products]); + + const goBackToPreviousPage = () => { + navigate(-2); + }; + + if (cartStatus === 'loading') return
Loading...
; + if (cartStatus === 'failed') return
Error loading cart items.
; return ( @@ -60,21 +68,20 @@ const MyBagPage: React.FC = () => { {products.length === 0 ? ( 장바구니에 담긴 물품이 없습니다. ) : ( - products.map((product, index) => ( + products.map((cartItem, index) => ( - {product.title} - {product.description} + {cartItem.productName} + {cartItem.description} - ${Number(product.price).toFixed(1)} + ${Number(cartItem.price).toFixed(1)} handleDecreaseQuantity(index)}>- - {Number(product.quantity) || 1} + {Number(cartItem.count) || 1} handleIncreaseQuantity(index)}>+ @@ -83,7 +90,6 @@ const MyBagPage: React.FC = () => { )) )} - 쇼핑 계속하기 diff --git a/src/store/cartSlice.ts b/src/store/cartSlice.ts index 9c9fec3..08d2033 100644 --- a/src/store/cartSlice.ts +++ b/src/store/cartSlice.ts @@ -1,41 +1,54 @@ -import { createAction, createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { ProductInterface } from '../models/product'; -import { useState } from 'react'; +import { createAction, createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { CartfetchProducts } from '../api/cartAPI'; + +export const fetchCartProducts = createAsyncThunk( + 'cart/fetchProducts', + async () => { + const response = await CartfetchProducts(); + return response; + } + ); export const addToCart = createAction<{ - product: ProductInterface, - quantity: number, - option: string // New field to represent the selected size option - }>("cart/add"); -// createAction<{ product: ProductInterface, quantity: number }>("cart/add"); + productID: number, + count: number, + optionID: string +}>("cart/add"); + +interface CartItem { + productID: number; + count: number; + optionID: string; +} interface CartState { - products: ProductInterface[]; + products: CartItem[]; + status: 'idle' | 'loading' | 'succeeded' | 'failed'; + error: string | null; } // 초기 장바구니 상태 정의 const initialState: CartState = { products: [], + status: 'idle', + error: null }; + // 장바구니에 대한 슬라이스 생성 const cartSlice = createSlice({ name: 'cart', initialState, reducers: { - // 상품 목록 설정 - setProducts: (state, action: PayloadAction) => { - state.products = action.payload; - }, // 상품 수량 증가 increaseQuantity: (state, action: PayloadAction) => { - const currentQuantity = Number(state.products[action.payload].quantity) || 0; - state.products[action.payload].quantity = currentQuantity + 1; + const currentQuantity = state.products[action.payload].count || 0; + state.products[action.payload].count = currentQuantity + 1; }, // 상품 수량 감소 (최소 1로 유지) decreaseQuantity: (state, action: PayloadAction) => { - const currentQuantity = Number(state.products[action.payload].quantity) || 0; - state.products[action.payload].quantity = Math.max(1, currentQuantity - 1); + const currentQuantity = state.products[action.payload].count || 0; + state.products[action.payload].count = Math.max(1, currentQuantity - 1); }, // 상품 삭제 removeProduct: (state, action: PayloadAction) => { @@ -44,20 +57,36 @@ const cartSlice = createSlice({ }, extraReducers: (builder) => { - builder.addCase(addToCart, (state, action) => { + builder + .addCase(fetchCartProducts.pending, (state) => { + state.status = 'loading'; + }) + .addCase(fetchCartProducts.fulfilled, (state, action) => { + state.status = 'succeeded'; + state.products = action.payload; + }) + .addCase(fetchCartProducts.rejected, (state, action) => { + state.status = 'failed'; + // state.error = action.error.message; + }) + .addCase(addToCart, (state, action) => { const existingProduct = state.products.find( - product => product.id === action.payload.product.id && product.option === action.payload.option + product => product.productID === action.payload.productID && product.optionID === action.payload.optionID ); if (existingProduct) { - existingProduct.quantity += action.payload.quantity; + existingProduct.count += action.payload.count; } else { - state.products.push({ ...action.payload.product, quantity: action.payload.quantity, option: action.payload.option }); + state.products.push({ + productID: action.payload.productID, + count: action.payload.count, + optionID: action.payload.optionID + }); } }); -} + } }); -export const { setProducts, increaseQuantity, decreaseQuantity, removeProduct } = cartSlice.actions; +export const { increaseQuantity, decreaseQuantity, removeProduct } = cartSlice.actions; export default cartSlice.reducer; \ No newline at end of file