Fixed image preview. Fixed Price Filter.
This commit is contained in:
@@ -5,6 +5,7 @@ import Item from "../../components/Item";
|
|||||||
import { useBasket } from "../BasketProvider";
|
import { useBasket } from "../BasketProvider";
|
||||||
import "../helper.css";
|
import "../helper.css";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
export default function ItemCard({ item }: { item: Item }) {
|
export default function ItemCard({ item }: { item: Item }) {
|
||||||
|
|
||||||
@@ -20,13 +21,29 @@ export default function ItemCard({ item }: { item: Item }) {
|
|||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
navigate(`/product/${item.id}`, { state: { item } });
|
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 (
|
return (
|
||||||
<Paper elevation={4}>
|
<Paper elevation={4}>
|
||||||
<Card>
|
<Card sx={{height: "100%", width: "100%" }}>
|
||||||
<CardActionArea onClick={handleClick}>
|
<CardActionArea onClick={handleClick} sx={{ height: "100%" }}>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
component="img"
|
component="img"
|
||||||
height="140"
|
height="140"
|
||||||
@@ -35,6 +52,11 @@ export default function ItemCard({ item }: { item: Item }) {
|
|||||||
onError={(event) => {
|
onError={(event) => {
|
||||||
event.currentTarget.src = "/src/assets/default.jpg"; // Standardbild setzen
|
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>
|
<CardContent>
|
||||||
<Typography gutterBottom variant="h5" component="div">
|
<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} />
|
<Rating name="half-rating" readOnly defaultValue={item.rating} precision={0.5} />
|
||||||
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end" }}>
|
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end" }}>
|
||||||
<Typography variant="body2" sx={{ color: 'text.secondary' }} className="item-description">
|
<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>
|
</Typography>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label={t('addToCart')}
|
aria-label={t('addToCart')}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Slider, Typography, Box } from "@mui/material";
|
import { Slider, Typography, Box } from "@mui/material";
|
||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type PriceSliderProps = {
|
type PriceSliderProps = {
|
||||||
@@ -8,11 +8,16 @@ type PriceSliderProps = {
|
|||||||
onChange?: (range: [number, number]) => void;
|
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 { t } = useTranslation();
|
||||||
const [value, setValue] = useState<[number, number]>([min, max]);
|
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[]) => {
|
const handleChange = (_: Event, newValue: number | number[]) => {
|
||||||
if (Array.isArray(newValue)) {
|
if (Array.isArray(newValue)) {
|
||||||
setValue([newValue[0], newValue[1]]);
|
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[]) => {
|
const handleCommitted = (_: Event, newValue: number | number[]) => {
|
||||||
if (Array.isArray(newValue)) {
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>{t('price')}</h3>
|
<h3>{t('price')}</h3>
|
||||||
<Box sx={{pl: 1, pr: 1}}>
|
<Box sx={{ pl: 1, pr: 1 }}>
|
||||||
<Slider
|
<Slider
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onChangeCommitted={handleCommitted}
|
onChangeCommitted={handleCommitted}
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
|
valueLabelFormat={formatValueToEuro} // Formatierung der Werte in Euro
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
step={1}
|
step={1}
|
||||||
/>
|
/>
|
||||||
</Box>
|
<Typography>
|
||||||
<Box sx={{display: 'flex', justifyContent: 'space-between'}}>
|
{formatValueToEuro(value[0])} - {formatValueToEuro(value[1])}
|
||||||
<Typography>{value[0]?.toFixed(2) ?? "0.00"} €</Typography>
|
</Typography>
|
||||||
<Typography>{value[1]?.toFixed(2) ?? "0.00"} €</Typography>
|
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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 { 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 { useBasket } from "../BasketProvider";
|
||||||
import {useTranslation} from "react-i18next";
|
|
||||||
|
|
||||||
export default function ProductInfo({ item }: { item: Item }) {
|
export default function ProductInfo({ item }: { item: Item }) {
|
||||||
|
|
||||||
@@ -53,7 +53,23 @@ export default function ProductInfo({ item }: { item: Item }) {
|
|||||||
setImageDimensions({ width: naturalWidth, height: naturalHeight });
|
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 (
|
return (
|
||||||
<Grid container spacing={4}>
|
<Grid container spacing={4}>
|
||||||
@@ -89,7 +105,7 @@ export default function ProductInfo({ item }: { item: Item }) {
|
|||||||
<Box display="flex" alignItems="center" gap={1}>
|
<Box display="flex" alignItems="center" gap={1}>
|
||||||
<Rating value={item.rating} precision={0.5} readOnly />
|
<Rating value={item.rating} precision={0.5} readOnly />
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
{item.rating > 0 ? `(${item.rating} / 5)`: t('noRatingsYet')}
|
{item.rating > 0 ? `(${item.rating} / 5)` : t('noRatingsYet')}
|
||||||
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -98,14 +114,14 @@ export default function ProductInfo({ item }: { item: Item }) {
|
|||||||
{item.discount100 > 0 ? (
|
{item.discount100 > 0 ? (
|
||||||
<>
|
<>
|
||||||
<Typography variant="h4" color="green">
|
<Typography variant="h4" color="green">
|
||||||
{discountedPrice.toFixed(2)} €
|
{(discountedPrice / 100).toFixed(2)} €
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
variant="h6"
|
variant="h6"
|
||||||
color="text.secondary"
|
color="text.secondary"
|
||||||
sx={{ textDecoration: 'line-through' }}
|
sx={{ textDecoration: 'line-through' }}
|
||||||
>
|
>
|
||||||
{item.price100.toFixed(2)} €
|
{(item.price100 / 100).toFixed(2)} €
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" color="error">
|
<Typography variant="h6" color="error">
|
||||||
-{item.discount100} %
|
-{item.discount100} %
|
||||||
@@ -113,7 +129,7 @@ export default function ProductInfo({ item }: { item: Item }) {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Typography variant="h4" color="green">
|
<Typography variant="h4" color="green">
|
||||||
{item.price100.toFixed(2)} €
|
{(item.price100 / 100).toFixed(2)} €
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import RatingSubmitType from "../../components/RatingSubmit";
|
import RatingSubmitType from "../../components/RatingSubmit";
|
||||||
|
|
||||||
export const fetchItemList = async () => {
|
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);
|
console.log("API Response:", response);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Fehler beim Laden der Items');
|
throw new Error('Fehler beim Laden der Items');
|
||||||
|
|||||||
Reference in New Issue
Block a user