Skip to content

Commit

Permalink
Исправление отображения товаров после редактирования и функционала до…
Browse files Browse the repository at this point in the history
…бавления в корзину.
  • Loading branch information
Иван Лайер committed Oct 29, 2024
1 parent 3b2499e commit 559942b
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 29 deletions.
26 changes: 12 additions & 14 deletions src/entities/ViewProduct/ViewProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { addToCart, dellFromCart, getCountInCartById, TProductInCartWithCount }
import { useAppSelector } from "../../store/hooks";
import { useForm } from "react-hook-form";
import { Product, TUpdateProductParams } from "../ViewProductList/model/types/types";
import { productDelete } from "../../store/slices/saga/deleteProductSaga";

export interface IViewProductProps {
product: Product;
isLast: boolean;
isEditMode: boolean;
onSaveChanges: (product: TUpdateProductParams) => void;
onSaveChanges: (product: Product) => void;
nextPage: () => void;
}

Expand All @@ -25,7 +26,7 @@ export const ViewProduct: FC<IViewProductProps> = ({ product, isLast, isEditMode
const containerRef = useRef();
const [isGroupOpen, setIsGroupOpen] = useState(false);

const { register, handleSubmit } = useForm({
const { register, handleSubmit } = useForm<Product>({
defaultValues: { ...product }
});

Expand All @@ -43,19 +44,13 @@ export const ViewProduct: FC<IViewProductProps> = ({ product, isLast, isEditMode
}
}, [containerRef]);

const handleDelete = () => {
dispatch(productDelete(product.id));
}

return (
<form onSubmit={handleSubmit((data) => {

const updateProduct : TUpdateProductParams = {
id: data.id,
name: data.name,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
price: data.price,
commandId: data.commandId,
categoryId: data.category.id
}
onSaveChanges(updateProduct);
onSaveChanges(data);
})
}
>
Expand Down Expand Up @@ -99,7 +94,10 @@ export const ViewProduct: FC<IViewProductProps> = ({ product, isLast, isEditMode
</GroupCollapse>

{isEditMode ?
<button type="submit" >Сохранить изменения</button>
<>
<button type="submit" >Сохранить изменения</button>
<button type="button" onClick={handleDelete}>Удалить</button>
</>
:
<div className={s.addToCartButton}>
<AddToCart
Expand Down
9 changes: 5 additions & 4 deletions src/entities/ViewProductList/ViewProductList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { ViewProduct } from "../ViewProduct/ViewProduct";
import s from './ViewProductList.module.sass';
import { putProductApi } from "./api/request";
import { useAppDispatch, useAppSelector } from "../../store/hooks";
import { Category, TUpdateProductParams } from "./model/types/types";
import { Category, Product, TUpdateProductParams } from "./model/types/types";
import { AddProductModal } from "./ui/AddProductModal/AddProductModal";
import { CategoryModal } from "./ui/CategoryModal";
import { productGet } from "../../store/slices/saga/getProductSaga";
import { productUpdate } from "../../store/slices/saga/updateProductSaga";

interface IViewProductListProps {
isEditMode: boolean;
Expand Down Expand Up @@ -55,8 +56,8 @@ export const ViewProductList = ({ isEditMode }: IViewProductListProps) => {
setIsOpenAddProductModal(true);
}

const handleSaveChanges = (product: TUpdateProductParams) => {
putProductApi(product)
const handleSaveChanges = (product: Product) => {
dispatcher(productUpdate(product));
}

return (
Expand All @@ -68,7 +69,7 @@ export const ViewProductList = ({ isEditMode }: IViewProductListProps) => {
</button>
}
{
productList.map((p, index) =>
productList.map((p, index) =>
<ViewProduct
product={p}
key={p.id + index}
Expand Down
4 changes: 4 additions & 0 deletions src/entities/ViewProductList/api/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,7 @@ export const addProductApi = async (param: TAddProductParams) => {
export const putProductApi = async( product: TUpdateProductParams) => {
const response = await axiosInstance.put(`/products/${product.id}`, product);
}

export const deleteProductApi = async( id: string) => {
const response = await axiosInstance.delete(`/products/${id}`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { LabelWrapper } from "../../../../shared/LabelWrapper";
import { z } from 'zod';
import s from './AddProductModal.modal.sass';
import { zodResolver } from '@hookform/resolvers/zod';
import axiosInstance from "../../../../shared/axiosHelper/axiosHelper";
import { useAppDispatch } from "../../../../store/hooks";
import { productAdd } from "../../../../store/slices/saga/addProductSaga";

const schema = z.object({
name: z.string().min(3, { message: 'Минимальная длина имени товара 3 символа' }),
Expand All @@ -28,6 +31,8 @@ export interface IAddProductModalProps {
}

export const AddProductModal = ({ isOpen, category, onAddCategory, onClose }: IAddProductModalProps) => {
const dispatcher = useAppDispatch();

const {
register,
handleSubmit,
Expand All @@ -54,12 +59,26 @@ export const AddProductModal = ({ isOpen, category, onAddCategory, onClose }: IA
const newProduct: TAddProductParams = {
name: data.name,
price: data.price,
categoryId: category ? category.id : "unknown",
categoryId: category ? category.id : null,
photo: data.photo,
desc: data.desc,
oldPrice: data.oldPrice,
}
addProductApi(newProduct);
dispatcher(productAdd(newProduct))

onClose();
}

const handleChangePhoto = async (e: React.ChangeEvent<HTMLInputElement>) => {
const [file] = e.target.files;
const formData = new FormData();
formData.append('file', file);

const response = await axiosInstance.post('/upload', formData);
return response.data.url;
};


return (
<>
{/* Модальное окно */}
Expand All @@ -73,7 +92,11 @@ export const AddProductModal = ({ isOpen, category, onAddCategory, onClose }: IA
{errors.name && <p className={s.red}>{errors.name.message}</p>}

<LabelWrapper title={"Фото"} required={true}>
<input {...register("photo")} />
<input type="file" onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleChangePhoto(e).then((url) => {
setValue("photo", url);
});
}} />
</LabelWrapper>
{errors.photo && <p className={s.red}>{errors.photo.message}</p>}

Expand Down
6 changes: 6 additions & 0 deletions src/store/mainStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import { takeEvery } from "redux-saga/effects";
import { doProfileRegisterSaga, PROFILE_REGISTER } from "./slices/saga/authAndProfileSaga";
import { doProfileUpdateSaga, PROFILE_UPDATE } from "./slices/saga/profileUpdateSaga";
import { getProductSaga, PRODUCT_GET } from "./slices/saga/getProductSaga";
import { PRODUCT_UPDATE, updateProductSaga } from "./slices/saga/updateProductSaga";
import { PRODUCT_DELETE, deleteProductSaga } from "./slices/saga/deleteProductSaga";
import { PRODUCT_ADD, addProductSaga } from "./slices/saga/addProductSaga";

const sagaMiddleware = createSagaMiddleware();

function* sagas() {
yield takeEvery(PROFILE_REGISTER, doProfileRegisterSaga);
yield takeEvery(PROFILE_UPDATE, doProfileUpdateSaga);
yield takeEvery(PRODUCT_GET, getProductSaga);
yield takeEvery(PRODUCT_UPDATE, updateProductSaga);
yield takeEvery(PRODUCT_DELETE, deleteProductSaga);
yield takeEvery(PRODUCT_ADD, addProductSaga);
}

const store = configureStore({
Expand Down
1 change: 0 additions & 1 deletion src/store/slices/productInCartSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const productInCartSlice = createSlice(
initialState,
reducers: {
addToCart(state, action: PayloadAction<TProductInCartWithCount>) {
//let found = state.productList.find(p => p.id == action.payload.id);
let found = false;
state.productList.forEach(p => {
if (p.id == action.payload.id) {
Expand Down
18 changes: 14 additions & 4 deletions src/store/slices/productSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { Product, Sorting } from "../../entities/ViewProductList/model/types/types";
import { Product, Sorting, TUpdateProductParams } from "../../entities/ViewProductList/model/types/types";

type TError = {
isError: boolean;
Expand Down Expand Up @@ -45,15 +45,24 @@ const productSlice = createSlice(
name: 'product',
initialState,
reducers: {
addToProductList(state, action: PayloadAction<Product>) {
state.productList.push(action.payload);
addToTopOfProductList(state, action: PayloadAction<Product>) {
state.productList.unshift(action.payload);
},
addProductsToList(state, action: PayloadAction<Product[]>) {
state.productList.push(...action.payload);
},
cleanProductList(state) {
state.productList = [];
},
updateProductList(state, action: PayloadAction<Product>) {
const foundIndex = state.productList.findIndex(p => p.id == action.payload.id);
if (foundIndex != -1) {
state.productList[foundIndex] = action.payload;
};
},
deleteProduct(state, action: PayloadAction<string>) {
state.productList = state.productList.filter(p => p.id != action.payload);
},
setCurrentPage(state, action: PayloadAction<number>) {
state.pagination.currentPage = action.payload;
},
Expand All @@ -70,4 +79,5 @@ const productSlice = createSlice(

export default productSlice.reducer;

export const { addToProductList, addProductsToList, cleanProductList, setCurrentPage, setIsLoading, setError } = productSlice.actions;
export const { addToTopOfProductList, addProductsToList, cleanProductList, deleteProduct,
updateProductList, setCurrentPage, setIsLoading, setError } = productSlice.actions;
29 changes: 29 additions & 0 deletions src/store/slices/saga/addProductSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { call, put } from "redux-saga/effects";
import { isTErrorResponse, TServerError } from "../../../shared/fetchHelpers/typeGuards";
import { createAction } from "@reduxjs/toolkit";
import { UNKNOWN_ERROR_MESSAGE } from "./constant";
import { Category, Product, TAddProductParams, TUpdateProductParams } from "../../../entities/ViewProductList/model/types/types";
import { addProductApi, putProductApi } from "../../../entities/ViewProductList/api/request";
import { setError, cleanProductList } from "../productSlice";
import { productGet } from "./getProductSaga";

// Saga Effects. Add product
export function* addProductSaga(data: { type: string, payload: TAddProductParams }): any {
try {
yield addProductApi(data.payload);
yield put(cleanProductList())
yield call(productGet, { pageSize: 10, pageNumber: 1, sorting: { type: 'ASC', field: 'id' } });
} catch (error: unknown) {
if (isTErrorResponse(error)) {
let allErrors = "";
error.response.data.errors.forEach((e: TServerError) => allErrors += e.message);

yield put(setError({ isError: true, errorMessage: allErrors }))
} else {
yield put(setError({ isError: true, errorMessage: UNKNOWN_ERROR_MESSAGE }))
}
}
}

export const PRODUCT_ADD = 'product/addProduct';
export const productAdd = createAction<TAddProductParams>(PRODUCT_ADD);
27 changes: 27 additions & 0 deletions src/store/slices/saga/deleteProductSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { put } from "redux-saga/effects";
import { isTErrorResponse, TServerError } from "../../../shared/fetchHelpers/typeGuards";
import { createAction } from "@reduxjs/toolkit";
import { UNKNOWN_ERROR_MESSAGE } from "./constant";
import { deleteProductApi } from "../../../entities/ViewProductList/api/request";
import { deleteProduct, setError } from "../productSlice";

// Saga Effects. Delete product
export function* deleteProductSaga(data: { type: string, payload: string }): any {
try {

yield deleteProductApi(data.payload);
yield put(deleteProduct(data.payload));
} catch (error: unknown) {
if (isTErrorResponse(error)) {
let allErrors = "";
error.response.data.errors.forEach((e: TServerError) => allErrors += e.message);

yield put(setError({ isError: true, errorMessage: allErrors }))
} else {
yield put(setError({ isError: true, errorMessage: UNKNOWN_ERROR_MESSAGE }))
}
}
}

export const PRODUCT_DELETE = 'product/deleteProduct';
export const productDelete = createAction<string>(PRODUCT_DELETE);
5 changes: 2 additions & 3 deletions src/store/slices/saga/getProductSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { put } from "redux-saga/effects";
import { isTErrorResponse, TServerError } from "../../../shared/fetchHelpers/typeGuards";
import { createAction } from "@reduxjs/toolkit";
import { UNKNOWN_ERROR_MESSAGE } from "./constant";
import { Product, Sorting, TProductRaw } from "../../../entities/ViewProductList/model/types/types";
import { Product, Sorting } from "../../../entities/ViewProductList/model/types/types";
import { getProductsApi } from "../../../entities/ViewProductList/api/request";
import { addProductsToList, addToProductList, setError, setIsLoading } from "../productSlice";
import { addProductsToList, setError, setIsLoading } from "../productSlice";
import { RawProductDto, TProductGetRaw } from "../../../entities/ViewProductList/model/types/productTypes";

export type TGetProductSagaProps = {
Expand All @@ -13,7 +13,6 @@ export type TGetProductSagaProps = {
sorting: Sorting;
}


// Saga Effects. get product
export function* getProductSaga(data: { type: string, payload: TGetProductSagaProps }): any {
try {
Expand Down
38 changes: 38 additions & 0 deletions src/store/slices/saga/updateProductSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { put } from "redux-saga/effects";
import { isTErrorResponse, TServerError } from "../../../shared/fetchHelpers/typeGuards";
import { createAction } from "@reduxjs/toolkit";
import { UNKNOWN_ERROR_MESSAGE } from "./constant";
import { Category, Product, TUpdateProductParams } from "../../../entities/ViewProductList/model/types/types";
import { putProductApi } from "../../../entities/ViewProductList/api/request";
import { setError, updateProductList } from "../productSlice";

// Saga Effects. Update product
export function* updateProductSaga(data: { type: string, payload: Product }): any {
try {

const updateProduct: TUpdateProductParams = {
id: data.payload.id,
name: data.payload.name,
createdAt: data.payload.createdAt,
updatedAt: data.payload.updatedAt,
price: data.payload.price,
categoryId: data.payload.category.id,
commandId: data.payload.commandId,
}

yield putProductApi(updateProduct);
yield put(updateProductList(data.payload));
} catch (error: unknown) {
if (isTErrorResponse(error)) {
let allErrors = "";
error.response.data.errors.forEach((e: TServerError) => allErrors += e.message);

yield put(setError({ isError: true, errorMessage: allErrors }))
} else {
yield put(setError({ isError: true, errorMessage: UNKNOWN_ERROR_MESSAGE }))
}
}
}

export const PRODUCT_UPDATE = 'product/updateProduct';
export const productUpdate = createAction<Product>(PRODUCT_UPDATE);

0 comments on commit 559942b

Please sign in to comment.