From dbe654d82953f42d0cc03cf1978c3ad1ecc4f9e3 Mon Sep 17 00:00:00 2001 From: Laura Dolibois Date: Sat, 31 May 2025 17:54:55 +0200 Subject: [PATCH] added slider as price filter --- 01-frontend/package-lock.json | 78 +++++++++---------- 01-frontend/package.json | 2 +- .../src/helper/homepage/PriceSlider.tsx | 48 ++++++++++++ 01-frontend/src/pages/Home.tsx | 75 +++++++++++------- package-lock.json | 6 ++ 5 files changed, 139 insertions(+), 70 deletions(-) create mode 100644 01-frontend/src/helper/homepage/PriceSlider.tsx create mode 100644 package-lock.json diff --git a/01-frontend/package-lock.json b/01-frontend/package-lock.json index 9deb6a7..b4a9466 100644 --- a/01-frontend/package-lock.json +++ b/01-frontend/package-lock.json @@ -11,7 +11,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@mui/icons-material": "^7.0.2", - "@mui/material": "^7.0.2", + "@mui/material": "^7.1.0", "i18next": "^25.2.0", "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", @@ -1173,9 +1173,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.0.2.tgz", - "integrity": "sha512-TfeFU9TgN1N06hyb/pV/63FfO34nijZRMqgHk0TJ3gkl4Fbd+wZ73+ZtOd7jag6hMmzO9HSrBc6Vdn591nhkAg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.0.tgz", + "integrity": "sha512-E0OqhZv548Qdc0PwWhLVA2zmjJZSTvaL4ZhoswmI8NJEC1tpW2js6LLP827jrW9MEiXYdz3QS6+hask83w74yQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -1209,16 +1209,16 @@ } }, "node_modules/@mui/material": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.0.2.tgz", - "integrity": "sha512-rjJlJ13+3LdLfobRplkXbjIFEIkn6LgpetgU/Cs3Xd8qINCCQK9qXQIjjQ6P0FXFTPFzEVMj0VgBR1mN+FhOcA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.1.0.tgz", + "integrity": "sha512-ahUJdrhEv+mCp4XHW+tHIEYzZMSRLg8z4AjUOsj44QpD1ZaMxQoVOG2xiHvLFdcsIPbgSRx1bg1eQSheHBgvtg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0", - "@mui/core-downloads-tracker": "^7.0.2", - "@mui/system": "^7.0.2", - "@mui/types": "^7.4.1", - "@mui/utils": "^7.0.2", + "@babel/runtime": "^7.27.1", + "@mui/core-downloads-tracker": "^7.1.0", + "@mui/system": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", @@ -1237,7 +1237,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.0.2", + "@mui/material-pigment-css": "^7.1.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1258,13 +1258,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.0.2.tgz", - "integrity": "sha512-6lt8heDC9wN8YaRqEdhqnm0cFCv08AMf4IlttFvOVn7ZdKd81PNpD/rEtPGLLwQAFyyKSxBG4/2XCgpbcdNKiA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.1.0.tgz", + "integrity": "sha512-4Kck4jxhqF6YxNwJdSae1WgDfXVg0lIH6JVJ7gtuFfuKcQCgomJxPvUEOySTFRPz1IZzwz5OAcToskRdffElDA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0", - "@mui/utils": "^7.0.2", + "@babel/runtime": "^7.27.1", + "@mui/utils": "^7.1.0", "prop-types": "^15.8.1" }, "engines": { @@ -1285,12 +1285,12 @@ } }, "node_modules/@mui/styled-engine": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.0.2.tgz", - "integrity": "sha512-11Bt4YdHGlh7sB8P75S9mRCUxTlgv7HGbr0UKz6m6Z9KLeiw1Bm9y/t3iqLLVMvSHYB6zL8X8X+LmfTE++gyBw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.1.0.tgz", + "integrity": "sha512-m0mJ0c6iRC+f9hMeRe0W7zZX1wme3oUX0+XTVHjPG7DJz6OdQ6K/ggEOq7ZdwilcpdsDUwwMfOmvO71qDkYd2w==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0", + "@babel/runtime": "^7.27.1", "@emotion/cache": "^11.13.5", "@emotion/serialize": "^1.3.3", "@emotion/sheet": "^1.4.0", @@ -1319,16 +1319,16 @@ } }, "node_modules/@mui/system": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.0.2.tgz", - "integrity": "sha512-yFUraAWYWuKIISPPEVPSQ1NLeqmTT4qiQ+ktmyS8LO/KwHxB+NNVOacEZaIofh5x1NxY8rzphvU5X2heRZ/RDA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.1.0.tgz", + "integrity": "sha512-iedAWgRJMCxeMHvkEhsDlbvkK+qKf9me6ofsf7twk/jfT4P1ImVf7Rwb5VubEA0sikrVL+1SkoZM41M4+LNAVA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0", - "@mui/private-theming": "^7.0.2", - "@mui/styled-engine": "^7.0.2", - "@mui/types": "^7.4.1", - "@mui/utils": "^7.0.2", + "@babel/runtime": "^7.27.1", + "@mui/private-theming": "^7.1.0", + "@mui/styled-engine": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1359,12 +1359,12 @@ } }, "node_modules/@mui/types": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz", - "integrity": "sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz", + "integrity": "sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0" + "@babel/runtime": "^7.27.1" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1376,13 +1376,13 @@ } }, "node_modules/@mui/utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz", - "integrity": "sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.0", - "@mui/types": "^7.4.1", + "@babel/runtime": "^7.27.1", + "@mui/types": "^7.4.2", "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", diff --git a/01-frontend/package.json b/01-frontend/package.json index a97d500..20e0a5c 100644 --- a/01-frontend/package.json +++ b/01-frontend/package.json @@ -14,7 +14,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@mui/icons-material": "^7.0.2", - "@mui/material": "^7.0.2", + "@mui/material": "^7.1.0", "i18next": "^25.2.0", "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", diff --git a/01-frontend/src/helper/homepage/PriceSlider.tsx b/01-frontend/src/helper/homepage/PriceSlider.tsx new file mode 100644 index 0000000..c1810ce --- /dev/null +++ b/01-frontend/src/helper/homepage/PriceSlider.tsx @@ -0,0 +1,48 @@ +import { Slider, Typography, Box } from "@mui/material"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; + +type PriceSliderProps = { + min?: number; + max?: number; + onChange?: (range: [number, number]) => void; +}; + +export default function PriceSlider({ min = 0, max = 100, onChange }: PriceSliderProps) { + + const { t } = useTranslation(); + const [value, setValue] = useState<[number, number]>([min, max]); + + const handleChange = (_: Event, newValue: number | number[]) => { + if (Array.isArray(newValue)) { + setValue([newValue[0], newValue[1]]); + } + }; + + const handleCommitted = (_: Event, newValue: number | number[]) => { + if (Array.isArray(newValue)) { + onChange?.([newValue[0], newValue[1]]); + } + }; + + return ( +
+

{t('price')}

+ + + + + {value[0]?.toFixed(2) ?? "0.00"} € + {value[1]?.toFixed(2) ?? "0.00"} € + +
+ ); +} diff --git a/01-frontend/src/pages/Home.tsx b/01-frontend/src/pages/Home.tsx index 084d92b..d1608a8 100644 --- a/01-frontend/src/pages/Home.tsx +++ b/01-frontend/src/pages/Home.tsx @@ -5,7 +5,8 @@ import FilterItem from "../helper/homepage/FilterItem"; import ItemCard from "../helper/homepage/ItemCard"; import "./pages.css"; // Import der CSS-Datei import { useLocation } from "react-router-dom"; -import {useTranslation} from "react-i18next"; +import { useTranslation } from "react-i18next"; +import PriceSlider from "../helper/homepage/PriceSlider"; export default function Home() { @@ -18,7 +19,7 @@ export default function Home() { description: "Description 1", price: 10, stock: 100, - category: "Category 1", + category: "Seeds", rating: 4.5, discount: 10, }, @@ -28,7 +29,7 @@ export default function Home() { description: "Description 2", price: 20, stock: 9, - category: "Category 2", + category: "GardenSupplies", rating: 4.0, discount: 20, }, @@ -38,7 +39,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 10, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -48,7 +49,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 0, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -58,7 +59,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -68,7 +69,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -78,7 +79,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -88,7 +89,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -98,7 +99,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -108,7 +109,7 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, @@ -118,19 +119,19 @@ export default function Home() { description: "Description 3", price: 30, stock: 300, - category: "Category 3", + category: "TechnicalComponents", rating: 4.8, discount: 15, }, { id: "12", - name: "Item 3", + name: "Item 4", description: "Description 3", - price: 30, + price: 50, stock: 300, - category: "Category 3", + category: "Other", rating: 4.8, - discount: 15, + discount: 0, }, // Weitere Items hinzufügen ]; @@ -143,13 +144,6 @@ export default function Home() { { value: "Other", label: t("other") } ]; - const priceFilter = [ - { value: "", label: t("all") }, - { value: "< 10", label: "< 10 €" }, - { value: "< 20", label: "< 20 €" }, - { value: ">= 20", label: "≥ 20 €" } - ]; - const ratingFilter = [ { value: "", label: t("all") }, ...[5, 4, 3, 2, 1].map(value => ({ @@ -162,9 +156,13 @@ export default function Home() { const [itemsPerPage, setItemsPerPage] = useState(9); // Dynamische Anzahl der Items pro Seite const [visibleItems, setVisibleItems] = useState([]); // Zustand für die sichtbaren Items const [selectedCategory, setSelectedCategory] = useState(null); - const [selectedPrice, setSelectedPrice] = useState(null); const [selectedRating, setSelectedRating] = useState(null); + const discountedPrices = items.map(item => item.price * (1 - item.discount / 100)); + const minPrice = Math.min(...discountedPrices); + const maxPrice = Math.max(...discountedPrices); + const [priceRange, setPriceRange] = useState<[number, number]>([minPrice, maxPrice]); + const location = useLocation(); useEffect(() => { @@ -192,7 +190,22 @@ export default function Home() { const newItemsPerPage = calculateItemsPerPage(); setItemsPerPage(newItemsPerPage); const startIndex = (currentPage - 1) * newItemsPerPage; - setVisibleItems(items.slice(startIndex, startIndex + newItemsPerPage)); + + const filtered = items + .filter(item => { + const discountedPrice = item.price * (1 - item.discount / 100); + return discountedPrice >= priceRange[0] && discountedPrice <= priceRange[1]; + }) + .filter(item => { + if (!selectedCategory) return true; + return item.category === selectedCategory; + }) + .filter(item => { + if (!selectedRating) return true; + return Math.floor(item.rating) === Number(selectedRating); + }); + + setVisibleItems(filtered.slice(startIndex, startIndex + newItemsPerPage)); }; updateItems(); // Initialer Aufruf @@ -219,11 +232,13 @@ export default function Home() { value={selectedCategory} onChange={handleCategoryChange} /> - { + setPriceRange(range); + setCurrentPage(1); + }} />