Fixed image preview. Fixed Price Filter.

This commit is contained in:
FlorianSpeicher
2025-06-04 00:48:31 +02:00
parent dffb97a416
commit 69f6c8b818
4 changed files with 71 additions and 24 deletions

View File

@@ -5,6 +5,7 @@ import Item from "../../components/Item";
import { useBasket } from "../BasketProvider";
import "../helper.css";
import { useTranslation } from 'react-i18next';
import { useEffect, useMemo, useRef, useState } from "react";
export default function ItemCard({ item }: { item: Item }) {
@@ -20,13 +21,29 @@ export default function ItemCard({ item }: { item: Item }) {
const handleClick = () => {
navigate(`/product/${item.id}`, { state: { item } });
}
const [imageUrl, setImageUrl] = useState<string>("/src/assets/default.jpg"); // Fallback-Bild
useEffect(() => {
const fetchImage = async () => {
try {
const response = await fetch(`http://localhost:8085/image?uuid=${item.uuid}`);
const data = await response.json();
if (data.uri) {
setImageUrl(data.uri); // Bild-URL setzen
}
} catch (error) {
console.error("Fehler beim Laden des Bildes:", error);
}
};
fetchImage();
}, [item.uuid]);
const imageUrl = `http://localhost:8085/image?articleId=${item.id}`;
return (
<Paper elevation={4}>
<Card>
<CardActionArea onClick={handleClick}>
<Card sx={{height: "100%", width: "100%" }}>
<CardActionArea onClick={handleClick} sx={{ height: "100%" }}>
<CardMedia
component="img"
height="140"
@@ -35,6 +52,11 @@ export default function ItemCard({ item }: { item: Item }) {
onError={(event) => {
event.currentTarget.src = "/src/assets/default.jpg"; // Standardbild setzen
}}
sx={{
objectFit: "contain", // Bild wird skaliert, um vollständig sichtbar zu sein
maxWidth: "100%", // Begrenze die maximale Breite auf den Container
maxHeight: "100%", // Begrenze die maximale Höhe auf den Container
}}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="div">
@@ -43,7 +65,7 @@ export default function ItemCard({ item }: { item: Item }) {
<Rating name="half-rating" readOnly defaultValue={item.rating} precision={0.5} />
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end" }}>
<Typography variant="body2" sx={{ color: 'text.secondary' }} className="item-description">
{(item.price100 * (1 - item.discount100 / 100)).toFixed(2)}
{(item.price100 / 100 * (1 - item.discount100 / 100)).toFixed(2)}
</Typography>
<IconButton
aria-label={t('addToCart')}

View File

@@ -1,5 +1,5 @@
import { Slider, Typography, Box } from "@mui/material";
import { useState } from "react";
import { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
type PriceSliderProps = {
@@ -8,11 +8,16 @@ type PriceSliderProps = {
onChange?: (range: [number, number]) => void;
};
export default function PriceSlider({ min = 0, max = 100, onChange }: PriceSliderProps) {
export default function PriceSlider({ min = 0, max = 10000, onChange }: PriceSliderProps) {
const { t } = useTranslation();
const [value, setValue] = useState<[number, number]>([min, max]);
// Synchronisiere den Zustand nur, wenn sich die Props ändern
useEffect(() => {
setValue([min, max]);
onChange?.([min, max]); // Initiale Werte an die übergeordnete Komponente übergeben
}, [min, max]);
const handleChange = (_: Event, newValue: number | number[]) => {
if (Array.isArray(newValue)) {
setValue([newValue[0], newValue[1]]);
@@ -21,27 +26,31 @@ export default function PriceSlider({ min = 0, max = 100, onChange }: PriceSlide
const handleCommitted = (_: Event, newValue: number | number[]) => {
if (Array.isArray(newValue)) {
onChange?.([newValue[0], newValue[1]]);
onChange?.([newValue[0], newValue[1]]); // Übergebe die neuen Werte an die übergeordnete Komponente
}
};
const formatValueToEuro = (value: number) => {
return `${(value / 100).toFixed(2)}`; // Umrechnung von Cent in Euro
};
return (
<div>
<h3>{t('price')}</h3>
<Box sx={{pl: 1, pr: 1}}>
<Box sx={{ pl: 1, pr: 1 }}>
<Slider
value={value}
onChange={handleChange}
onChangeCommitted={handleCommitted}
valueLabelDisplay="auto"
valueLabelFormat={formatValueToEuro} // Formatierung der Werte in Euro
min={min}
max={max}
step={1}
/>
</Box>
<Box sx={{display: 'flex', justifyContent: 'space-between'}}>
<Typography>{value[0]?.toFixed(2) ?? "0.00"} </Typography>
<Typography>{value[1]?.toFixed(2) ?? "0.00"} </Typography>
<Typography>
{formatValueToEuro(value[0])} - {formatValueToEuro(value[1])}
</Typography>
</Box>
</div>
);

View File

@@ -1,9 +1,9 @@
import { Alert, Box, Button, Card, Divider, Grid, IconButton, Rating, Snackbar, SnackbarCloseReason, Stack, TextField, Typography } from "@mui/material";
import Item from "../../components/Item";
import React, { useState } from "react";
import { Close, LocalShipping, ShoppingCart } from "@mui/icons-material";
import { Alert, Box, Button, Card, Divider, Grid, IconButton, Rating, Snackbar, SnackbarCloseReason, Stack, TextField, Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import Item from "../../components/Item";
import { useBasket } from "../BasketProvider";
import {useTranslation} from "react-i18next";
export default function ProductInfo({ item }: { item: Item }) {
@@ -53,7 +53,23 @@ export default function ProductInfo({ item }: { item: Item }) {
setImageDimensions({ width: naturalWidth, height: naturalHeight });
};
const imageUrl = `http://localhost:8085/image?articleId=${item.id}`;
const [imageUrl, setImageUrl] = useState<string>("/src/assets/default.jpg"); // Fallback-Bild
useEffect(() => {
const fetchImage = async () => {
try {
const response = await fetch(`http://localhost:8085/image?uuid=${item.uuid}`);
const data = await response.json();
if (data.uri) {
setImageUrl(data.uri); // Bild-URL setzen
}
} catch (error) {
console.error("Fehler beim Laden des Bildes:", error);
}
};
fetchImage();
}, [item.uuid]);
return (
<Grid container spacing={4}>
@@ -89,8 +105,8 @@ export default function ProductInfo({ item }: { item: Item }) {
<Box display="flex" alignItems="center" gap={1}>
<Rating value={item.rating} precision={0.5} readOnly />
<Typography variant="body2" color="text.secondary">
{item.rating > 0 ? `(${item.rating} / 5)`: t('noRatingsYet')}
{item.rating > 0 ? `(${item.rating} / 5)` : t('noRatingsYet')}
</Typography>
</Box>
@@ -98,14 +114,14 @@ export default function ProductInfo({ item }: { item: Item }) {
{item.discount100 > 0 ? (
<>
<Typography variant="h4" color="green">
{discountedPrice.toFixed(2)}
{(discountedPrice / 100).toFixed(2)}
</Typography>
<Typography
variant="h6"
color="text.secondary"
sx={{ textDecoration: 'line-through' }}
>
{item.price100.toFixed(2)}
{(item.price100 / 100).toFixed(2)}
</Typography>
<Typography variant="h6" color="error">
-{item.discount100} %
@@ -113,7 +129,7 @@ export default function ProductInfo({ item }: { item: Item }) {
</>
) : (
<Typography variant="h4" color="green">
{item.price100.toFixed(2)}
{(item.price100 / 100).toFixed(2)}
</Typography>
)}
</Stack>

View File

@@ -3,7 +3,7 @@
import RatingSubmitType from "../../components/RatingSubmit";
export const fetchItemList = async () => {
const response = await fetch('http://localhost:8085/item/all');
const response = await fetch('http://localhost:8085/article/all');
console.log("API Response:", response);
if (!response.ok) {
throw new Error('Fehler beim Laden der Items');