feat(client): add resize button and status badge to GalleryGrid
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
|
import AutoFixHighOutlinedIcon from '@mui/icons-material/AutoFixHighOutlined'
|
||||||
|
import CheckCircleOutlineOutlinedIcon from '@mui/icons-material/CheckCircleOutlineOutlined'
|
||||||
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'
|
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined'
|
||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
|
import Chip from '@mui/material/Chip'
|
||||||
import IconButton from '@mui/material/IconButton'
|
import IconButton from '@mui/material/IconButton'
|
||||||
import Tooltip from '@mui/material/Tooltip'
|
import Tooltip from '@mui/material/Tooltip'
|
||||||
import { OptimizedImage } from '@/shared/ui/OptimizedImage'
|
import { OptimizedImage } from '@/shared/ui/OptimizedImage'
|
||||||
@@ -8,10 +11,12 @@ import type { GalleryImageItem } from '../model/types'
|
|||||||
type Props = {
|
type Props = {
|
||||||
items: GalleryImageItem[]
|
items: GalleryImageItem[]
|
||||||
deleting?: boolean
|
deleting?: boolean
|
||||||
|
resizing?: string | null
|
||||||
onDelete: (id: string) => void
|
onDelete: (id: string) => void
|
||||||
|
onResize: (id: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GalleryGrid({ items, deleting, onDelete }: Props) {
|
export function GalleryGrid({ items, deleting, resizing, onDelete, onResize }: Props) {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@@ -38,23 +43,56 @@ export function GalleryGrid({ items, deleting, onDelete }: Props) {
|
|||||||
sizes="140px"
|
sizes="140px"
|
||||||
sx={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
|
sx={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
|
||||||
/>
|
/>
|
||||||
<Tooltip title="Удалить из галереи">
|
<Box sx={{ position: 'absolute', top: 4, left: 4 }}>
|
||||||
<IconButton
|
{item.isResized ? (
|
||||||
size="small"
|
<Chip
|
||||||
color="error"
|
label="Готово"
|
||||||
sx={{
|
size="small"
|
||||||
position: 'absolute',
|
color="success"
|
||||||
top: 4,
|
icon={<CheckCircleOutlineOutlinedIcon fontSize="small" />}
|
||||||
right: 4,
|
sx={{ height: 24, '& .MuiChip-label': { px: 0.75 }, '& .MuiChip-icon': { fontSize: 14, ml: 0.5 } }}
|
||||||
bgcolor: 'background.paper',
|
/>
|
||||||
'&:hover': { bgcolor: 'error.light', color: 'error.contrastText' },
|
) : (
|
||||||
}}
|
<Chip
|
||||||
disabled={deleting}
|
label="Не обработано"
|
||||||
onClick={() => onDelete(item.id)}
|
size="small"
|
||||||
>
|
color="warning"
|
||||||
<DeleteOutlineOutlinedIcon fontSize="small" />
|
sx={{ height: 24, '& .MuiChip-label': { px: 0.75 } }}
|
||||||
</IconButton>
|
/>
|
||||||
</Tooltip>
|
)}
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ position: 'absolute', top: 4, right: 4, display: 'flex', gap: 0.5 }}>
|
||||||
|
{!item.isResized && (
|
||||||
|
<Tooltip title="Обработать (resize)">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
sx={{
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
'&:hover': { bgcolor: 'primary.light', color: 'primary.contrastText' },
|
||||||
|
}}
|
||||||
|
disabled={resizing === item.id}
|
||||||
|
onClick={() => onResize(item.id)}
|
||||||
|
>
|
||||||
|
<AutoFixHighOutlinedIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<Tooltip title="Удалить из галереи">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
sx={{
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
'&:hover': { bgcolor: 'error.light', color: 'error.contrastText' },
|
||||||
|
}}
|
||||||
|
disabled={deleting}
|
||||||
|
onClick={() => onDelete(item.id)}
|
||||||
|
>
|
||||||
|
<DeleteOutlineOutlinedIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Stack from '@mui/material/Stack'
|
|||||||
import Typography from '@mui/material/Typography'
|
import Typography from '@mui/material/Typography'
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import { fetchAdminCatalogSlider } from '@/entities/catalog-slider'
|
import { fetchAdminCatalogSlider } from '@/entities/catalog-slider'
|
||||||
import { deleteGalleryImage, fetchAdminGallery, GalleryGrid } from '@/entities/gallery'
|
import { deleteGalleryImage, fetchAdminGallery, GalleryGrid, resizeGalleryImage } from '@/entities/gallery'
|
||||||
import { uploadAdminProductImages } from '@/entities/product/api/product-api'
|
import { uploadAdminProductImages } from '@/entities/product/api/product-api'
|
||||||
import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
|
import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
|
||||||
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
|
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
|
||||||
@@ -50,6 +50,13 @@ export function AdminGalleryPage() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const resizeMut = useMutation({
|
||||||
|
mutationFn: (id: string) => resizeGalleryImage(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
void invalidateQueryKeys(queryClient, [['admin', 'gallery'], ['admin', 'catalog-slider'], ['catalog-slider']])
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const items = galleryQuery.data?.items ?? []
|
const items = galleryQuery.data?.items ?? []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -122,7 +129,13 @@ export function AdminGalleryPage() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<GalleryGrid items={items} deleting={deleteMut.isPending} onDelete={(id) => deleteMut.mutate(id)} />
|
<GalleryGrid
|
||||||
|
items={items}
|
||||||
|
deleting={deleteMut.isPending}
|
||||||
|
resizing={resizeMut.isPending ? (resizeMut.variables ?? null) : null}
|
||||||
|
onDelete={(id) => deleteMut.mutate(id)}
|
||||||
|
onResize={(id) => resizeMut.mutate(id)}
|
||||||
|
/>
|
||||||
|
|
||||||
{!galleryQuery.isLoading && items.length === 0 && (
|
{!galleryQuery.isLoading && items.length === 0 && (
|
||||||
<Typography color="text.secondary">Пока нет загруженных изображений.</Typography>
|
<Typography color="text.secondary">Пока нет загруженных изображений.</Typography>
|
||||||
|
|||||||
Reference in New Issue
Block a user