{product.name}
diff --git a/front/src/features/catalog/productsSlice.ts b/front/src/features/catalog/productsSlice.ts index 17c4591..acbabd6 100644 --- a/front/src/features/catalog/productsSlice.ts +++ b/front/src/features/catalog/productsSlice.ts @@ -32,6 +32,14 @@ export const fetchProductsByCategory = createAsyncThunk( } ); +export const fetchProductById = createAsyncThunk( + "product/fetchById", + async (id: string) => { + const response = await axios.get(`/api/products/${id}`); + return response.data; + } +); + interface ProductsState { items: Product[]; total: number; diff --git a/front/src/pages/ItemPage/ItemPage.module.css b/front/src/pages/ItemPage/ItemPage.module.css new file mode 100644 index 0000000..e627a65 --- /dev/null +++ b/front/src/pages/ItemPage/ItemPage.module.css @@ -0,0 +1,93 @@ +.page { + background: #f5f5f5; + min-height: 100vh; +} + +.top { + background: #000; + padding: 15px 40px; +} + +.back { + color: white; + background: none; + border: none; + cursor: pointer; + font-weight: 600; +} + +.hero { + display: flex; + min-height: 500px; +} + +.left { + flex: 1; + background: #fff; + display: flex; + align-items: center; + justify-content: center; +} + +.left img { + max-width: 400px; +} + +.right { + flex: 1; + background: linear-gradient( + rgba(0, 0, 0, 0.7), + rgba(0, 0, 0, 0.7) + ), + url("/bg.jpg"); + color: white; + padding: 80px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.breadcrumbs { + color: #f5c400; + margin-bottom: 20px; +} + +.download { + margin-top: 30px; + background: #f5c400; + border: none; + padding: 15px 40px; + border-radius: 30px; + font-weight: bold; + cursor: pointer; +} + +.tabs { + display: flex; + border-top: 1px solid #ddd; +} + +.tabs button { + flex: 1; + padding: 20px; + border: none; + background: #eee; + cursor: pointer; +} + +.active { + background: white; + font-weight: bold; +} + +.content { + padding: 40px; + background: white; +} + +.attrRow { + display: flex; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid #eee; +} \ No newline at end of file diff --git a/front/src/pages/ItemPage/ItemPage.tsx b/front/src/pages/ItemPage/ItemPage.tsx new file mode 100644 index 0000000..fb25f80 --- /dev/null +++ b/front/src/pages/ItemPage/ItemPage.tsx @@ -0,0 +1,96 @@ +import { useEffect, useState } from "react"; +import { useParams, useNavigate } from "react-router-dom"; +import { useAppDispatch, useAppSelector } from "../../app/hooks"; +import { fetchProductById } from "../../features/catalog/productsSlice"; +import styles from "./ProductPage.module.css"; +//import type { Product } from "../../types/product"; +import type { CategoryAtributes } from "../../types/categories"; + +const ItemPage = () => { + const { id } = useParams(); + const dispatch = useAppDispatch(); + const navigate = useNavigate(); + const { items, loading } = useAppSelector((state) => state.products); + const { items: cats, selectedCategoryId } = useAppSelector(s => s.categories); + //const filters = useAppSelector(s => s.products.filtersApplied); + + const [activeTab, setActiveTab] = useState<"desc" | "chars">("desc"); + + useEffect(() => { + if (id) dispatch(fetchProductById(id)); + }, [id]); + + const product = items.find((item) => item.id === Number(id)); + const category = cats.find((cat) => cat.id === Number(selectedCategoryId)) + + if ((loading || !product)) return{product.description}
+ + +{product.description}
+