This commit is contained in:
@kirill.komarov
2026-05-11 20:42:26 +05:00
parent 212484d062
commit 130c12a1d3
9 changed files with 48 additions and 9 deletions
+10 -1
View File
@@ -1,6 +1,7 @@
import type { Category, Product } from '@/entities/product/model/types'
import { apiClient } from '@/shared/api/client'
import { apiBaseURL } from '@/shared/config'
import { ADMIN_UPLOAD_IMAGE_MAX_BYTES, formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
export type PublicProductsResponse = {
items: Product[]
@@ -119,8 +120,16 @@ export async function deleteAdminCategory(id: string): Promise<void> {
/** FormData: не задавать Content-Type вручную (boundary задаёт браузер). */
export async function uploadAdminProductImages(files: FileList | readonly File[]): Promise<string[]> {
const list = Array.from(files)
for (const f of list) {
if (f.size > ADMIN_UPLOAD_IMAGE_MAX_BYTES) {
throw new Error(
`Файл «${f.name}» слишком большой (максимум ${formatAdminImageMaxSizeHint()} на одно изображение).`,
)
}
}
const fd = new FormData()
for (const f of Array.from(files)) {
for (const f of list) {
fd.append('files', f, f.name)
}
const token = localStorage.getItem('craftshop_auth_token')
@@ -11,6 +11,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { fetchAdminCatalogSlider } from '@/entities/catalog-slider/api/catalog-slider-api'
import { deleteGalleryImage, fetchAdminGallery } from '@/entities/gallery/api/gallery-api'
import { uploadAdminProductImages } from '@/entities/product/api/product-api'
import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
import { GallerySliderSection } from './GallerySliderSection'
@@ -80,6 +81,10 @@ export function AdminGalleryPage() {
<Divider sx={{ mb: 3 }} />
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
Форматы: PNG, JPEG, WebP. На один файл до {formatAdminImageMaxSizeHint()}.
</Typography>
<Stack direction="row" spacing={2} sx={{ mb: 3, alignItems: 'center', flexWrap: 'wrap' }}>
<Button variant="contained" component="label" disabled={uploadMut.isPending}>
Загрузить файлы
+3 -1
View File
@@ -40,6 +40,7 @@ import {
uploadAdminProductImages,
} from '@/entities/product/api/product-api'
import type { Category, Product } from '@/entities/product/model/types'
import { formatAdminImageMaxSizeHint } from '@/shared/constants/upload-limits'
import { formatPriceRub } from '@/shared/lib/format-price'
import { getErrorMessage } from '@/shared/lib/get-error-message'
import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys'
@@ -535,7 +536,8 @@ export function AdminPage() {
Фото (загрузка)
</Typography>
<FormHelperText sx={{ mt: 0, mb: 1 }}>
Крестик на превью убирает фото только из карточки; файл остаётся на сервере и в галерее.
PNG, JPEG или WebP, до {formatAdminImageMaxSizeHint()} на файл. Крестик на превью убирает фото только из
карточки; файл остаётся на сервере и в галерее.
</FormHelperText>
<Box
sx={{
@@ -0,0 +1,6 @@
/** Должно совпадать с `getProductImageMaxFileBytes()` на сервере (по умолчанию 20 МБ). */
export const ADMIN_UPLOAD_IMAGE_MAX_BYTES = 20 * 1024 * 1024
export function formatAdminImageMaxSizeHint(): string {
return `${Math.round(ADMIN_UPLOAD_IMAGE_MAX_BYTES / (1024 * 1024))} МБ`
}