Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

장바구니 영역 API 400대 에러 발생 , 소스만 반영 후 Commit 처리 #48

Open
wants to merge 1 commit into
base: devMain
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/api/cartAPI.ts
Original file line number Diff line number Diff line change
@@ -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;
}
};
100 changes: 53 additions & 47 deletions src/pages/MyBagPage.tsx
Original file line number Diff line number Diff line change
@@ -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<ProductInterface>('cart/add');
// export const addToCart = createAction<fetchCartProducts>('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 <div>Loading...</div>;
if (cartStatus === 'failed') return <div>Error loading cart items.</div>;

return (
<MyBagPageContainer>
Expand All @@ -60,21 +68,20 @@ const MyBagPage: React.FC = () => {
{products.length === 0 ? (
<EmptyMessage>장바구니에 담긴 물품이 없습니다.</EmptyMessage>
) : (
products.map((product, index) => (
products.map((cartItem, index) => (
<ProductCard key={index}>
<ProductImage
src='https://img.29cm.co.kr/next-product/2023/05/03/03eafb89a29045bd818b3600b2bcae18_20230503165832.jpg?width=700'
// src={product.thumbnail} 이미지 url이 제대로 안나와서 제가 다른걸로 일단 넣어놓겠습니다 ㅠㅠ
alt={product.title}
src='https://img.29cm.co.kr/next-product/2023/05/03/03eafb89a29045bd818b3600b2bcae18_20230503165832.jpg'
alt={cartItem.productName || "Product"}
/>
<ProductDetails>
<ProductName>{product.title}</ProductName>
<ProductDescription>{product.description}</ProductDescription>
<ProductName>{cartItem.productName}</ProductName>
<ProductDescription>{cartItem.description}</ProductDescription>
<ProductPriceAndQuantity>
<ProductPrice>${Number(product.price).toFixed(1)}</ProductPrice>
<ProductPrice>${Number(cartItem.price).toFixed(1)}</ProductPrice>
<QuantityButtons>
<QuantityButton onClick={() => handleDecreaseQuantity(index)}>-</QuantityButton>
<Quantity>{Number(product.quantity) || 1}</Quantity>
<Quantity>{Number(cartItem.count) || 1}</Quantity>
<QuantityButton onClick={() => handleIncreaseQuantity(index)}>+</QuantityButton>
</QuantityButtons>
</ProductPriceAndQuantity>
Expand All @@ -83,7 +90,6 @@ const MyBagPage: React.FC = () => {
</ProductCard>
))
)}

<ButtonContainer>
<ContinueShoppingButton onClick={goBackToPreviousPage}>
쇼핑 계속하기
Expand Down
75 changes: 52 additions & 23 deletions src/store/cartSlice.ts
Original file line number Diff line number Diff line change
@@ -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<ProductInterface[]>) => {
state.products = action.payload;
},
// 상품 수량 증가
increaseQuantity: (state, action: PayloadAction<number>) => {
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<number>) => {
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<number>) => {
Expand All @@ -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;