добавил поиск по slug исправил логику подгрузки конкретного товара
This commit is contained in:
1 parent
a585a6a823
commit
090b641906
6 files changed
+54
-31
No files matched your search
+1
-1
@@ -15,7 +15,7 @@ function AppRoutes() {
|
||||
<Route path="about" element={<About />} />
|
||||
<Route path="products" element={<Products />} />
|
||||
<Route path="contacts" element={<Contacts />} />
|
||||
<Route path="/product/:id" element={<ItemPage />} />
|
||||
<Route path="/product/:slug" element={<ItemPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
)
|
||||
|
||||
@@ -2,31 +2,34 @@ import React from "react";
|
||||
import type { Product } from "../../types/product";
|
||||
import styles from "./Catalog.module.css";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { setSelectedProducts } from "./productsSlice";
|
||||
|
||||
|
||||
interface Props {
|
||||
product: Product;
|
||||
product: Product;
|
||||
}
|
||||
|
||||
const ProductCard: React.FC<Props> = ({ product }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onSelect = (prodId: number) => {
|
||||
navigate(`/product/${product.id}`);
|
||||
setSelectedProducts(prodId);
|
||||
}
|
||||
const onSelect = () => {
|
||||
navigate(`/product/${product.slug}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
className={`${styles.card} ${styles.productCard}`}
|
||||
onClick={() => onSelect(product.id)}
|
||||
onClick={() => onSelect()}
|
||||
>
|
||||
<div className={styles.productImageFrame}>
|
||||
<img className={styles.productImage} src={product.images[0]} alt={product.name} />
|
||||
<img
|
||||
className={styles.productImage}
|
||||
src={product.images[0]}
|
||||
alt={product.name}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.cardContent}>
|
||||
<p className={styles.name}>{product.name}</p>
|
||||
<button className={styles.plus}>+</button>
|
||||
<p className={styles.name}>{product.name}</p>
|
||||
<button className={styles.plus}>+</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -38,10 +38,10 @@ export const fetchProductsByCategory = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
export const fetchProductById = createAsyncThunk(
|
||||
"product/fetchById",
|
||||
async (id: string) => {
|
||||
const response = await client.get<Product>(`/products/${id}/`);
|
||||
export const fetchProductBySlug = createAsyncThunk(
|
||||
"product/fetchBySlug",
|
||||
async (slug: string) => {
|
||||
const response = await client.get<Product>(`/products/${slug}/`);
|
||||
return response.data;
|
||||
}
|
||||
);
|
||||
@@ -54,7 +54,8 @@ interface ProductsState {
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
filtersApplied: Record<string, (string|number)[]>;
|
||||
selectedProductId: number | null;
|
||||
selectedProduct: Product | null;
|
||||
//selectedProductId: number | null;
|
||||
}
|
||||
|
||||
const initialState: ProductsState = {
|
||||
@@ -65,16 +66,17 @@ const initialState: ProductsState = {
|
||||
loading: false,
|
||||
error: null,
|
||||
filtersApplied: {},
|
||||
selectedProductId: null
|
||||
selectedProduct: null
|
||||
//selectedProductId: null
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: "products",
|
||||
initialState,
|
||||
reducers: {
|
||||
setSelectedProducts(state, action: PayloadAction<number>){
|
||||
/*setSelectedProducts(state, action: PayloadAction<number>){
|
||||
state.selectedProductId = action.payload;
|
||||
},
|
||||
},*/
|
||||
setPage(state, action: PayloadAction<number>) {
|
||||
state.page = action.payload;
|
||||
},
|
||||
@@ -84,10 +86,14 @@ const slice = createSlice({
|
||||
setFilters(state, action: PayloadAction<ProductsState["filtersApplied"]>) {
|
||||
state.filtersApplied = action.payload;
|
||||
},
|
||||
setSelectedProduct(state, action: PayloadAction<Product | null>) {
|
||||
state.selectedProduct = action.payload;
|
||||
},
|
||||
resetProducts(state) {
|
||||
state.items = [];
|
||||
state.total = 0;
|
||||
state.page = 1;
|
||||
state.selectedProduct = null;
|
||||
}
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
@@ -106,9 +112,22 @@ const slice = createSlice({
|
||||
.addCase(fetchProductsByCategory.rejected, (s, a) => {
|
||||
s.loading = false;
|
||||
s.error = a.error.message ?? "Ошибка";
|
||||
})
|
||||
.addCase(fetchProductBySlug.pending, (s) => {
|
||||
s.loading = true;
|
||||
s.error = null;
|
||||
})
|
||||
.addCase(fetchProductBySlug.fulfilled, (s, a) => {
|
||||
s.loading = false;
|
||||
s.selectedProduct = a.payload;
|
||||
s.error = null;
|
||||
})
|
||||
.addCase(fetchProductBySlug.rejected, (s, a) => {
|
||||
s.loading = false;
|
||||
s.error = a.error.message ?? "Ошибка";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const { setPage, setLimit, setFilters, resetProducts, setSelectedProducts } = slice.actions;
|
||||
export default slice.reducer;
|
||||
export const { setPage, setLimit, setFilters, resetProducts } = slice.actions;
|
||||
export default slice.reducer;
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { ArrowLeftOutlined } from "@ant-design/icons";
|
||||
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||
import { fetchProductById } from "../../features/catalog/productsSlice";
|
||||
import { fetchProductBySlug } from "../../features/catalog/productsSlice";
|
||||
import styles from "./ItemPage.module.css";
|
||||
import Button from "../../components/Button/Button";
|
||||
import PriceLisForm from "../../components/PriceLisForm/PriceLisForm";
|
||||
@@ -11,20 +11,20 @@ import Link from "antd/es/typography/Link";
|
||||
import { setSelectedCategory } from "../../features/catalog/categoriesSlice";
|
||||
|
||||
const ItemPage = () => {
|
||||
const { id } = useParams();
|
||||
const { slug } = useParams();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { items, loading } = useAppSelector((state) => state.products);
|
||||
const { loading } = useAppSelector((state) => state.products);
|
||||
const { items: cats, selectedCategoryId } = useAppSelector((s) => s.categories);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<"desc" | "chars">("desc");
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) dispatch(fetchProductById(id));
|
||||
}, [dispatch, id]);
|
||||
if (slug) dispatch(fetchProductBySlug(slug));
|
||||
}, [dispatch, slug]);
|
||||
|
||||
const product = items.find((item) => item.id === Number(id));
|
||||
const product = useAppSelector((state) => state.products.selectedProduct);
|
||||
const category = cats.find((cat) => cat.id === Number(selectedCategoryId));
|
||||
|
||||
if (loading || !product) {
|
||||
|
||||
@@ -9,4 +9,5 @@ export interface Product {
|
||||
categoryId?: number;
|
||||
created_at: string;
|
||||
full_name: string;
|
||||
slug:string;
|
||||
}
|
||||
Reference in new issue
Block a user