Files
dps-webshop/01-frontend/src/pages/Home.tsx
2025-06-16 17:22:34 +02:00

184 lines
6.4 KiB
TypeScript

import { Alert, Box, useTheme } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
import ItemWithImage from "../components/Item";
import FilterItem from "../helper/homepage/FilterItem";
import ItemCard from "../helper/homepage/ItemCard";
import PriceSlider from "../helper/homepage/PriceSlider";
import { fetchItemListWithImage } from '../helper/query/Queries';
import "./pages.css"; // Import der CSS-Datei
export default function Home() {
const { t } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
const theme = useTheme();
const [searchQuery, setSearchQuery] = useState<string | null>(null);
const categoriesFilter = useMemo(() => [
{ value: "", label: t("allCategories") },
{ value: "Seeds", label: t("seeds") },
{ value: "GardenSupplies", label: t("gardenSupplies") },
{ value: "TechnicalComponents", label: t("technicalComponents") },
{ value: "Other", label: t("other") }
], [t]);
const ratingFilter = [
{ value: "", label: t('allRatings') },
...[5, 4, 3, 2, 1].map(value => ({
value: value.toString(),
label: value.toString()
}))
];
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [selectedRating, setSelectedRating] = useState<string | null>(null);
const { data = [] } = useQuery<ItemWithImage[]>({
queryKey: ['fetchItemListWithImage'],
queryFn: fetchItemListWithImage,
retry: 3, // Versucht es 3-mal erneut
retryDelay: 1000, // Wartezeit zwischen den Versuchen (in ms)
});
const items:ItemWithImage[] = useMemo(() => data || [], [data]);
const discountedPrices = items.map(
(item) => item.price100 * (1 - item.discount100 / 100)
);
const minPrice = discountedPrices.length > 0 ? Math.min(...discountedPrices) : 0;
const maxPrice = discountedPrices.length > 0 ? Math.max(...discountedPrices) : 1000;
const [priceRange, setPriceRange] = useState<[number, number]>([
minPrice,
maxPrice,
]);
// Filter aus URL übernehmen
useEffect(() => {
const params = new URLSearchParams(location.search);
const category = params.get("category");
if (category && categoriesFilter.some((f) => f.value === category)) {
setSelectedCategory(category);
} else {
setSelectedCategory(null);
}
}, [location.search, categoriesFilter]);
// Filterfunktion bleibt gleich
const filteredItems: ItemWithImage[] = useMemo(() => {return items
.filter((item) => {
const discountedPrice = item.price100 * (1 - item.discount100 / 100);
return discountedPrice >= priceRange[0] && discountedPrice <= priceRange[1];
})
.filter((item) => {
if (!selectedCategory) return true;
return item.category.toLowerCase() === selectedCategory.toLowerCase();
})
.filter((item) => {
if (!selectedRating) return true;
const rating = Math.trunc(item.rating);
return rating === (Number(selectedRating) * 2) -1 || rating === (Number(selectedRating) * 2);
})
.filter((item) => {
if (!searchQuery) return true;
return (item.name.toLowerCase().includes(searchQuery.toLowerCase())
);
});
}, [items, priceRange, selectedCategory, selectedRating, searchQuery]);
// Lese die Suchanfrage aus der URL
useEffect(() => {
const params = new URLSearchParams(location.search);
const query = params.get("search");
setSearchQuery(query);
}, [location.search]);
// Items, die aktuell angezeigt werden
const visibleItems: ItemWithImage[] = filteredItems;
// Container Ref
const containerRef = useRef<HTMLDivElement>(null);
const prevItemsLength = useRef(items.length);
useEffect(() => {
if (items.length >= prevItemsLength.current) {
prevItemsLength.current = items.length;
return;
}
setTimeout(() => {
containerRef.current?.scrollTo(0, 0);
}, 50);
prevItemsLength.current = items.length;
}, [items]);
// Kategorie-Änderung
const handleCategoryChange = (category: string) => {
if (category === "") {
setSelectedCategory(null);
navigate(`/`);
} else {
setSelectedCategory(category);
navigate(`/?category=${encodeURIComponent(category)}`);
}
};
// Rating-Änderung (bleibt gleich)
const handleRatingChange = (rating: string) => {
if (rating === "") {
setSelectedRating(null);
} else {
setSelectedRating(rating);
}
};
return (
<div
className="home-page-background"
style={{ backgroundColor: theme.palette.homepage }}
>
<div className="sidebar sidebar-filter">
<FilterItem
filterName={t("category")}
filterItems={categoriesFilter}
value={selectedCategory}
onChange={handleCategoryChange}
/>
<PriceSlider
min={minPrice}
max={maxPrice}
onChange={(range) => {
setPriceRange(range);
}}
/>
<FilterItem
filterName={t("rating")}
filterItems={ratingFilter}
value={selectedRating}
onChange={handleRatingChange}
/>
</div>
<div className="page-background page-background-center" ref={containerRef}>
<Box className="cardgrid">
{visibleItems.length === 0 ? (
<Alert variant="filled" severity="warning" className="no-results">{t('noItemsFound')}</Alert>
) : (
visibleItems.map((item) => (
<ItemCard key={item.id} item={item} />
))
)}
</Box>
</div>
</div>
);
}