base commit
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import StarRoundedIcon from '@mui/icons-material/StarRounded'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import Avatar from '@mui/material/Avatar'
|
||||
import Box from '@mui/material/Box'
|
||||
import Paper from '@mui/material/Paper'
|
||||
import Rating from '@mui/material/Rating'
|
||||
import Skeleton from '@mui/material/Skeleton'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Link as RouterLink } from 'react-router-dom'
|
||||
import { fetchLatestApprovedReviews } from '@/entities/product/api/reviews-api'
|
||||
|
||||
function initials(display: string) {
|
||||
const s = display.trim()
|
||||
if (!s) return '?'
|
||||
return s.slice(0, 1).toUpperCase()
|
||||
}
|
||||
|
||||
function formatReviewDate(iso: string): string {
|
||||
try {
|
||||
return new Date(iso).toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric' })
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export function ReviewsBlock() {
|
||||
const q = useQuery({
|
||||
queryKey: ['reviews', 'latest', 5],
|
||||
queryFn: () => fetchLatestApprovedReviews(5),
|
||||
})
|
||||
|
||||
const items = !q.isLoading && !q.isError && q.data ? q.data.items : []
|
||||
|
||||
return (
|
||||
<Paper variant="outlined" sx={{ p: { xs: 2, sm: 3 }, borderRadius: 2, bgcolor: 'background.paper' }}>
|
||||
<Stack spacing={0.75} sx={{ mb: 2 }}>
|
||||
<Typography variant="h5">Отзывы</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Последние одобренные отзывы о товарах
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
{q.isLoading && (
|
||||
<Stack spacing={2}>
|
||||
{[1, 2, 3].map((i) => (
|
||||
<Skeleton key={i} variant="rounded" height={92} sx={{ borderRadius: 2 }} />
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
{q.isError && <Alert severity="error">Не удалось загрузить отзывы.</Alert>}
|
||||
{!q.isLoading && !q.isError && q.data && items.length === 0 && (
|
||||
<Typography color="text.secondary">Пока нет опубликованных отзывов о товарах.</Typography>
|
||||
)}
|
||||
{items.length > 0 && (
|
||||
<Stack spacing={2}>
|
||||
{items.map((r, i) => {
|
||||
const zebra = i % 2 === 0
|
||||
const text = typeof r.text === 'string' && r.text.trim() ? r.text.trim() : 'Без комментария'
|
||||
return (
|
||||
<Paper
|
||||
key={r.id}
|
||||
variant={zebra ? undefined : 'outlined'}
|
||||
elevation={zebra ? 0 : undefined}
|
||||
sx={{
|
||||
p: { xs: 1.75, sm: 2 },
|
||||
borderRadius: 2,
|
||||
...(zebra ? { bgcolor: 'action.hover' } : {}),
|
||||
}}
|
||||
>
|
||||
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
||||
<Stack direction="row" spacing={1.5} sx={{ minWidth: { sm: 220 }, alignItems: 'center' }}>
|
||||
<Avatar sx={{ bgcolor: 'primary.main', color: 'primary.contrastText', fontWeight: 800 }}>
|
||||
{initials(r.authorDisplay)}
|
||||
</Avatar>
|
||||
<Box>
|
||||
<Typography sx={{ fontWeight: 800, lineHeight: 1.15 }}>{r.authorDisplay}</Typography>
|
||||
<Stack direction="row" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
<Rating
|
||||
value={r.rating}
|
||||
readOnly
|
||||
size="small"
|
||||
icon={<StarRoundedIcon fontSize="inherit" />}
|
||||
emptyIcon={<StarRoundedIcon fontSize="inherit" />}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{formatReviewDate(r.createdAt)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Typography
|
||||
variant="caption"
|
||||
component={RouterLink}
|
||||
to={`/products/${r.productId}`}
|
||||
sx={{
|
||||
display: 'block',
|
||||
mt: 0.25,
|
||||
color: 'primary.main',
|
||||
textDecoration: 'none',
|
||||
'&:hover': { textDecoration: 'underline' },
|
||||
}}
|
||||
>
|
||||
{r.productTitle}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
<Typography color="text.secondary" sx={{ whiteSpace: 'pre-wrap', flex: 1 }}>
|
||||
{text}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)
|
||||
})}
|
||||
</Stack>
|
||||
)}
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user