171 lines
4.2 KiB
TypeScript
171 lines
4.2 KiB
TypeScript
import {
|
|
Box,
|
|
Button,
|
|
Divider,
|
|
IconButton,
|
|
Rating,
|
|
Snackbar,
|
|
SnackbarCloseReason,
|
|
TextField,
|
|
Typography,
|
|
useTheme,
|
|
} from "@mui/material";
|
|
import { Close } from "@mui/icons-material";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import React, { useMemo, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import RatingType from "../../components/Rating";
|
|
import { fetchRatingList, submitRating } from "../query/Queries";
|
|
import RatingCard from "./RatingCard";
|
|
import RatingSubmitType from "../../components/RatingSubmit";
|
|
|
|
export default function Ratings({ itemId }: { itemId: string }) {
|
|
const { t } = useTranslation();
|
|
const theme = useTheme();
|
|
|
|
const [open, setOpen] = useState<boolean>(false);
|
|
const [ratingText, setRatingText] = useState<string>("");
|
|
const [ratingValue, setRatingValue] = useState<number | null>(2.5);
|
|
|
|
const ratingData: RatingSubmitType = {
|
|
rating: ratingValue || 0,
|
|
content: ratingText || "",
|
|
articleId: itemId,
|
|
};
|
|
|
|
const { refetch } = useQuery({
|
|
queryKey: ["submitRating", ratingData],
|
|
queryFn: () => submitRating(ratingData),
|
|
retry: 3,
|
|
retryDelay: 1000,
|
|
enabled: false,
|
|
});
|
|
|
|
const handleRatingSubmit = () => {
|
|
setOpen(true);
|
|
void refetch(); // bewusst ausgelöst, kein await notwendig
|
|
};
|
|
|
|
const handleClose = (
|
|
_: React.SyntheticEvent | Event,
|
|
reason?: SnackbarCloseReason,
|
|
) => {
|
|
if (reason === "clickaway") return;
|
|
setOpen(false);
|
|
};
|
|
|
|
const action = (
|
|
<React.Fragment>
|
|
<IconButton
|
|
size="small"
|
|
aria-label={t("close")}
|
|
color="inherit"
|
|
onClick={handleClose}
|
|
>
|
|
<Close fontSize="small" />
|
|
</IconButton>
|
|
</React.Fragment>
|
|
);
|
|
|
|
const { data = [] } = useQuery<RatingType[]>({
|
|
queryKey: ["fetchRatingList", itemId],
|
|
queryFn: () => fetchRatingList(itemId),
|
|
retry: 3,
|
|
retryDelay: 1000,
|
|
});
|
|
|
|
const ratings: RatingType[] = useMemo(() => data || [], [data]);
|
|
|
|
const getRatings = () => {
|
|
if (ratings.length === 0) {
|
|
return (
|
|
<Typography
|
|
variant="body1"
|
|
sx={{ color: theme.palette.text.secondary }}
|
|
>
|
|
{t("noRatingsYet")}
|
|
</Typography>
|
|
);
|
|
}
|
|
|
|
return ratings.map((ratingType: RatingType) => (
|
|
<RatingCard key={ratingType.timestamp} {...ratingType} />
|
|
));
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Divider sx={{ backgroundColor: theme.palette.divider, my: 3 }} />
|
|
|
|
<Box sx={{ mb: 4 }}>
|
|
<Typography
|
|
variant="h5"
|
|
sx={{ color: theme.palette.text.primary, mb: 2 }}
|
|
>
|
|
{t("rateThisProduct")}:
|
|
</Typography>
|
|
|
|
<Rating
|
|
name="half-rating"
|
|
value={ratingValue}
|
|
onChange={(_, value) => setRatingValue(value)}
|
|
precision={0.5}
|
|
/>
|
|
|
|
<TextField
|
|
label={t("review")}
|
|
multiline
|
|
minRows={4}
|
|
maxRows={16}
|
|
fullWidth
|
|
sx={{
|
|
mt: 2,
|
|
mb: 2,
|
|
backgroundColor: theme.palette.background.paper,
|
|
color: theme.palette.text.primary,
|
|
"& .MuiInputBase-input": {
|
|
color: theme.palette.text.primary,
|
|
},
|
|
"& label": {
|
|
color: theme.palette.text.secondary,
|
|
},
|
|
"& .MuiOutlinedInput-root": {
|
|
"& fieldset": {
|
|
borderColor: theme.palette.divider,
|
|
},
|
|
"&:hover fieldset": {
|
|
borderColor: theme.palette.text.primary,
|
|
},
|
|
"&.Mui-focused fieldset": {
|
|
borderColor: theme.palette.primary.main,
|
|
},
|
|
},
|
|
}}
|
|
value={ratingText}
|
|
onChange={(e) => setRatingText(e.target.value)}
|
|
/>
|
|
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
onClick={handleRatingSubmit}
|
|
>
|
|
{t("submit")}
|
|
</Button>
|
|
</Box>
|
|
|
|
<Divider sx={{ backgroundColor: theme.palette.divider, my: 3 }} />
|
|
|
|
<Box>{getRatings()}</Box>
|
|
|
|
<Snackbar
|
|
open={open}
|
|
autoHideDuration={3000}
|
|
onClose={handleClose}
|
|
message={t("thanksForRating")}
|
|
action={action}
|
|
/>
|
|
</>
|
|
);
|
|
}
|