"use client" import { useState, useRef } from 'react' import { useMutation, useQuery } from '@apollo/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Card } from '@/components/ui/card' import { CREATE_PRODUCT, UPDATE_PRODUCT } from '@/graphql/mutations' import { GET_CATEGORIES } from '@/graphql/queries' import { Upload, X, Star, Plus, Image as ImageIcon } from 'lucide-react' import { toast } from 'sonner' interface Product { id: string name: string article: string description: string price: number quantity: number category: { id: string; name: string } | null brand: string color: string size: string weight: number dimensions: string material: string images: string[] mainImage: string isActive: boolean } interface ProductFormProps { product?: Product | null onSave: () => void onCancel: () => void } export function ProductForm({ product, onSave, onCancel }: ProductFormProps) { const [formData, setFormData] = useState({ name: product?.name || '', article: product?.article || '', description: product?.description || '', price: product?.price || 0, quantity: product?.quantity || 0, categoryId: product?.category?.id || 'none', brand: product?.brand || '', color: product?.color || '', size: product?.size || '', weight: product?.weight || 0, dimensions: product?.dimensions || '', material: product?.material || '', images: product?.images || [], mainImage: product?.mainImage || '', isActive: product?.isActive ?? true }) const [isUploading, setIsUploading] = useState(false) const [uploadingImages, setUploadingImages] = useState>(new Set()) const fileInputRef = useRef(null) const [createProduct, { loading: creating }] = useMutation(CREATE_PRODUCT) const [updateProduct, { loading: updating }] = useMutation(UPDATE_PRODUCT) // Загружаем категории const { data: categoriesData } = useQuery(GET_CATEGORIES) const loading = creating || updating const handleInputChange = (field: string, value: string | number | boolean) => { setFormData(prev => ({ ...prev, [field]: value })) } const handleImageUpload = async (files: FileList) => { const newUploadingIndexes = new Set() const startIndex = formData.images.length // Добавляем плейсхолдеры для загружаемых изображений const placeholders = Array.from(files).map((_, index) => { newUploadingIndexes.add(startIndex + index) return '' // Пустой URL как плейсхолдер }) setUploadingImages(prev => new Set([...prev, ...newUploadingIndexes])) setFormData(prev => ({ ...prev, images: [...prev.images, ...placeholders] })) try { // Загружаем каждое изображение const uploadPromises = Array.from(files).map(async (file, index) => { const actualIndex = startIndex + index const formData = new FormData() formData.append('file', file) formData.append('type', 'product') const response = await fetch('/api/upload-file', { method: 'POST', body: formData }) if (!response.ok) { throw new Error('Ошибка загрузки изображения') } const result = await response.json() return { index: actualIndex, url: result.fileUrl } }) const results = await Promise.all(uploadPromises) // Обновляем URLs загруженных изображений setFormData(prev => { const newImages = [...prev.images] results.forEach(({ index, url }) => { newImages[index] = url }) return { ...prev, images: newImages, mainImage: prev.mainImage || results[0]?.url || '' // Устанавливаем первое изображение как главное } }) toast.success('Изображения успешно загружены') } catch (error) { console.error('Error uploading images:', error) toast.error('Ошибка загрузки изображений') // Удаляем неудачные плейсхолдеры setFormData(prev => ({ ...prev, images: prev.images.slice(0, startIndex) })) } finally { // Убираем индикаторы загрузки setUploadingImages(prev => { const updated = new Set(prev) newUploadingIndexes.forEach(index => updated.delete(index)) return updated }) } } const handleRemoveImage = (indexToRemove: number) => { setFormData(prev => { const newImages = prev.images.filter((_, index) => index !== indexToRemove) const removedImageUrl = prev.images[indexToRemove] return { ...prev, images: newImages, mainImage: prev.mainImage === removedImageUrl ? (newImages[0] || '') : prev.mainImage } }) } const handleSetMainImage = (imageUrl: string) => { setFormData(prev => ({ ...prev, mainImage: imageUrl })) } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!formData.name || !formData.article || formData.price <= 0) { toast.error('Пожалуйста, заполните все обязательные поля') return } try { const input = { name: formData.name, article: formData.article, description: formData.description || undefined, price: formData.price, quantity: formData.quantity, categoryId: formData.categoryId && formData.categoryId !== 'none' ? formData.categoryId : undefined, brand: formData.brand || undefined, color: formData.color || undefined, size: formData.size || undefined, weight: formData.weight || undefined, dimensions: formData.dimensions || undefined, material: formData.material || undefined, images: formData.images.filter(img => img), // Убираем пустые строки mainImage: formData.mainImage || undefined, isActive: formData.isActive } if (product) { await updateProduct({ variables: { id: product.id, input } }) toast.success('Товар успешно обновлен') } else { await createProduct({ variables: { input } }) toast.success('Товар успешно создан') } onSave() } catch (error: unknown) { console.error('Error saving product:', error) toast.error((error as Error).message || 'Ошибка при сохранении товара') } } return (
{/* Основная информация */}

Основная информация

handleInputChange('name', e.target.value)} placeholder="iPhone 15 Pro Max" className="glass-input text-white placeholder:text-white/40 h-10" required />
handleInputChange('article', e.target.value)} placeholder="IP15PM-256-BLU" className="glass-input text-white placeholder:text-white/40 h-10" required />