diff --git a/src/features/CartEdit/model/selectors.ts b/src/features/CartEdit/model/selectors.ts index 2963212e..6705e10c 100644 --- a/src/features/CartEdit/model/selectors.ts +++ b/src/features/CartEdit/model/selectors.ts @@ -1,7 +1,11 @@ import { StateSchema } from '@/app/providers/StoreProvider' -export const putIncreaseProductAmountSelector = (state: StateSchema) => { - return state.productAmount.isIncreaseSuccessful +export const isSuccessfulRequest = (state: StateSchema) => { + return ( + state.productAmount.isIncreaseSuccessful || + state.productAmount.isDecreaseSuccessful || + state.productAmount.isRemoveSuccessful + ) } export const getProductListSelector = (state: StateSchema) => { diff --git a/src/features/CartEdit/model/services/putRemoveProduct.ts b/src/features/CartEdit/model/services/putRemoveProduct.ts new file mode 100644 index 00000000..3957db0f --- /dev/null +++ b/src/features/CartEdit/model/services/putRemoveProduct.ts @@ -0,0 +1,26 @@ +import { createAsyncThunk } from '@reduxjs/toolkit' + +import { ThunkConfig } from '@/app/providers/StoreProvider/config/StateSchema' +import { apiErrorIdentify } from '@/shared/api/apiErrorIdentify' +import { ApiError, ApiErrorTypes, ApiRoutes } from '@/shared/api/types' + +export const putRemoveProduct = createAsyncThunk>( + 'cart-remove-product', + async (productId, thunkAPI) => { + const { rejectWithValue, extra } = thunkAPI + try { + const { data } = await extra.api.put( + `api/${ApiRoutes.REMOVE_PRODUCT}`, + { + product: productId + }, + { + withCredentials: true + } + ) + return data + } catch (error) { + return rejectWithValue(apiErrorIdentify(error, ApiErrorTypes.DATA_EMPTY_ERROR)) + } + } +) diff --git a/src/features/CartEdit/model/slice/productAmountSlice.ts b/src/features/CartEdit/model/slice/productAmountSlice.ts index 62ff426b..39634d24 100644 --- a/src/features/CartEdit/model/slice/productAmountSlice.ts +++ b/src/features/CartEdit/model/slice/productAmountSlice.ts @@ -4,10 +4,10 @@ import { rejectedPayloadHandle } from '@/shared/api/rejectedPayloadHandle' import { putDecreaseProductAmount } from '../services/putDecreaseProductAmount' import { putIncreaseProductAmount } from '../services/putIncreaseProductAmount' +import { putRemoveProduct } from '../services/putRemoveProduct' import { IProductAmountStateSchema } from '../types' const initialState: IProductAmountStateSchema = { - isIncreaseSuccessful: false, productList: { amount: 0, product: { @@ -25,7 +25,15 @@ const initialState: IProductAmountStateSchema = { full_price: 0, full_weight: 0 }, - isDecreaseSuccessful: false + isIncreaseSuccessful: false, + isDecreaseSuccessful: false, + isRemoveSuccessful: false +} + +function resetStatuses(state: IProductAmountStateSchema) { + state.isIncreaseSuccessful = false + state.isDecreaseSuccessful = false + state.isRemoveSuccessful = false } export const productAmountSlice = createSlice({ @@ -39,12 +47,10 @@ export const productAmountSlice = createSlice({ extraReducers: builder => { builder .addCase(putIncreaseProductAmount.pending, state => { - state.isIncreaseSuccessful = false - state.isDecreaseSuccessful = false + resetStatuses(state) }) - .addCase(putIncreaseProductAmount.fulfilled, (state, { payload }) => { + .addCase(putIncreaseProductAmount.fulfilled, state => { state.isIncreaseSuccessful = true - state.productList = payload }) .addCase(putIncreaseProductAmount.rejected, (state, { payload }) => { state.isIncreaseSuccessful = false @@ -52,16 +58,25 @@ export const productAmountSlice = createSlice({ }) .addCase(putDecreaseProductAmount.pending, state => { - state.isDecreaseSuccessful = false + resetStatuses(state) }) - .addCase(putDecreaseProductAmount.fulfilled, (state, { payload }) => { + .addCase(putDecreaseProductAmount.fulfilled, state => { state.isDecreaseSuccessful = true - state.productList = payload }) .addCase(putDecreaseProductAmount.rejected, (state, { payload }) => { state.isDecreaseSuccessful = false state.error = rejectedPayloadHandle(payload) }) + + .addCase(putRemoveProduct.pending, state => { + resetStatuses(state) + }) + .addCase(putRemoveProduct.fulfilled, state => { + state.isRemoveSuccessful = true + }) + .addCase(putRemoveProduct.rejected, state => { + state.isRemoveSuccessful = false + }) } }) diff --git a/src/features/CartEdit/model/types.ts b/src/features/CartEdit/model/types.ts index 55789200..b01589b5 100644 --- a/src/features/CartEdit/model/types.ts +++ b/src/features/CartEdit/model/types.ts @@ -3,6 +3,7 @@ import { IProductCartList } from '@/shared/model/types/ProductCartListModel' export interface IProductAmountStateSchema { isIncreaseSuccessful: boolean isDecreaseSuccessful: boolean + isRemoveSuccessful: boolean productList: IProductCartList error?: string | string[] } diff --git a/src/features/CartEdit/ui/CartEdit/CartEdit.stories.tsx b/src/features/CartEdit/ui/CartEdit/CartEdit.stories.tsx index d1ea00a6..e53d62d7 100644 --- a/src/features/CartEdit/ui/CartEdit/CartEdit.stories.tsx +++ b/src/features/CartEdit/ui/CartEdit/CartEdit.stories.tsx @@ -28,7 +28,7 @@ type Story = StoryObj export const Default: Story = { args: { cartId: 85, - productList: { + productWithInfo: { amount: 1, product: { id: 1, @@ -48,6 +48,7 @@ export const Default: Story = { }, full_price: 0, full_weight: 0 - } + }, + updateCart: () => {} } } diff --git a/src/features/CartEdit/ui/CartEdit/CartEdit.tsx b/src/features/CartEdit/ui/CartEdit/CartEdit.tsx index df0f7263..772d13ca 100644 --- a/src/features/CartEdit/ui/CartEdit/CartEdit.tsx +++ b/src/features/CartEdit/ui/CartEdit/CartEdit.tsx @@ -10,72 +10,82 @@ import ButtonDots from '@/shared/ui/ButtonDots/ButtonDots' import Paragraph from '@/shared/ui/Paragraph/Paragraph' import Subheading from '@/shared/ui/Subheading/Subheading' -import { getProductListSelector } from '../../model/selectors' +import { isSuccessfulRequest } from '../../model/selectors' import { putDecreaseProductAmount } from '../../model/services/putDecreaseProductAmount' import { putIncreaseProductAmount } from '../../model/services/putIncreaseProductAmount' -import { productAmountActions } from '../../model/slice/productAmountSlice' +import { putRemoveProduct } from '../../model/services/putRemoveProduct' import styles from './CartEdit.module.scss' export type TCartEditProps = { cartId: number - productList: IProductCartList + productWithInfo: IProductCartList + updateCart: () => void } /** * Компонент используется для отображения добавленных в корзину продуктов, изменения кол-ва продуктов в корзине, * для удаления продуктов из корзины, для добавления продуктов в закладки * @param {number} cartId - id корзины - * @param {IProductCartList} productList - это продукт для определения состояния + * @param {IProductCartList} productList - это корзина с количеством товара, общей стоимостью и весом + * @param {function} updateCart - это функция для обновления корзины */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const CartEdit: React.FC = ({ cartId, productList }: TCartEditProps) => { +export const CartEdit: React.FC = ({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + cartId, + productWithInfo, + updateCart +}: TCartEditProps) => { + const MIN_AMOUNT = 1 + const MAX_AMOUNT = 99 const [needToOpenContextMenuButtonDots, setNeedToOpen] = useState(false) const dispatch = useAppDispatch() - const productListState: IProductCartList = useSelector(getProductListSelector) + const isSuccessful: boolean = useSelector(isSuccessfulRequest) function deleteProductHandler() { setNeedToOpen(false) - // removeProduct(product.id) переделать на вызов action https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/319 + dispatch(putRemoveProduct(productWithInfo.product.id)) } + useEffect(() => { + updateCart() + }, [isSuccessful]) + function addToFavoritesHandler() { setNeedToOpen(false) } function increaseAmountHandler() { - dispatch(putIncreaseProductAmount(productListState.product.id)) + if (productWithInfo.amount < MAX_AMOUNT) { + dispatch(putIncreaseProductAmount(productWithInfo.product.id)) + } } function decreaseAmountHandler() { - dispatch(putDecreaseProductAmount(productListState.product.id)) - // tbd https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/318 + if (productWithInfo.amount > MIN_AMOUNT) { + dispatch(putDecreaseProductAmount(productWithInfo.product.id)) + } } function setAmountHandler() { //tbd https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/316 } - useEffect(() => { - dispatch(productAmountActions.setProductList(productList)) - }, [productList]) - return ( <>
- +
{' '} - {productListState.amount * Number(productListState.product.price)}{' '} - {productListState.product.brand} + {productWithInfo.amount * Number(productWithInfo.product.price)} {productWithInfo.product.brand} {/* currency, not brand, c Number непонятно пока*/} {' '} - {productListState.product.price} {productListState.product.brand}/шт + {productWithInfo.product.price} {productWithInfo.product.brand}/шт {/* currency, not brand */}
@@ -88,9 +98,9 @@ export const CartEdit: React.FC = ({ cartId, productList }: TCar diff --git a/src/pages/CartPage/CartPage.tsx b/src/pages/CartPage/CartPage.tsx index cfb03561..680e5b63 100644 --- a/src/pages/CartPage/CartPage.tsx +++ b/src/pages/CartPage/CartPage.tsx @@ -28,6 +28,10 @@ const CartPage = () => { dispatch(getCartList()) }, []) + function updateCart() { + dispatch(getCartList()) + } + return (
@@ -48,7 +52,14 @@ const CartPage = () => {
{cart.products.map(item => { - return + return ( + + ) })}
diff --git a/src/shared/api/types.ts b/src/shared/api/types.ts index bc674244..831fd5bc 100644 --- a/src/shared/api/types.ts +++ b/src/shared/api/types.ts @@ -14,7 +14,8 @@ export enum ApiRoutes { PRODUCT = 'catalogue', CART_LIST = 'cart', INCREASE_PRODUCT_AMOUNT = 'cart/add/', - DECREASE_PRODUCT_AMOUNT = 'cart/subtract/' + DECREASE_PRODUCT_AMOUNT = 'cart/subtract/', + REMOVE_PRODUCT = 'cart/delete/' } export enum ApiErrorTypes {