From dc00bca3902751271c94806f4d096fcd6b29bbae Mon Sep 17 00:00:00 2001 From: anibilag Date: Tue, 25 Mar 2025 22:33:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20?= =?UTF-8?q?=D0=B3=D0=B0=D0=BB=D0=B5=D1=80=D0=B5=D0=B5=D0=B9.=20=D0=A0?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=80=D1=8F=D0=B4=D0=BA=D0=B0=20=D0=B8=D0=B7=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9.=20=D0=9D=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/GalleryManager/index.tsx | 123 ++++++++++++------------ src/hooks/useGallery.ts | 6 +- src/pages/AdminPage.tsx | 76 +++++++++------ src/types/index.ts | 5 + 4 files changed, 117 insertions(+), 93 deletions(-) diff --git a/src/components/GalleryManager/index.tsx b/src/components/GalleryManager/index.tsx index 9a69526..c30cfbb 100644 --- a/src/components/GalleryManager/index.tsx +++ b/src/components/GalleryManager/index.tsx @@ -1,91 +1,92 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { GalleryImage } from '../../types'; import { GalleryGrid } from './GalleryGrid'; import { ImageForm } from './ImageForm'; -import { EditImageModal } from './EditImageModal'; + interface GalleryManagerProps { images: GalleryImage[]; +// setImages: (images: GalleryImage[]) => void; // Добавляем setter для изображений imageUrl: string; - onChange: (images: GalleryImage[]) => void; + setImageUrl: (url: string) => void; // Добавил setImageUrl для обновления + onAddImage: (imageData: Omit) => void; + onReorder: (images: GalleryImage[]) => void; + onDelete: (id: string) => void; + onEdit: (image: GalleryImage) => void; } -export function GalleryManager({ images, imageUrl, onChange }: GalleryManagerProps) { - const [editingImage, setEditingImage] = useState(null); +export function GalleryManager({ + images, + //setImages, + imageUrl, + setImageUrl, + onAddImage, + onReorder, + onDelete, + onEdit + }: GalleryManagerProps) { const [newImageUrl, setNewImageUrl] = useState(''); const [newImageCaption, setNewImageCaption] = useState(''); const [newImageAlt, setNewImageAlt] = useState(''); - const handleAddImage = () => { - setNewImageUrl(imageUrl); + // Следим за изменением imageUrl и обновляем newImageUrl + useEffect(() => { + if (imageUrl) { + setNewImageUrl(imageUrl); + } + }, [imageUrl]); + const handleAddImage = () => { if (!newImageUrl.trim()) return; - const newImage: GalleryImage = { - id: Date.now().toString(), + const newImage = { url: newImageUrl, caption: newImageCaption, - alt: newImageAlt || newImageCaption + alt: newImageAlt || newImageCaption, + width: 800, // Примерное значение, можно заменить на динамическое + height: 600, + size: 100000, // Примерное значение + format: 'webp', // Формат по умолчанию }; - onChange([...images, newImage]); + onAddImage(newImage); // Вызываем функцию добавления setNewImageUrl(''); setNewImageCaption(''); setNewImageAlt(''); - }; - - const handleUpdateImage = (updatedImage: GalleryImage) => { - onChange(images.map(img => img.id === updatedImage.id ? updatedImage : img)); - setEditingImage(null); - }; - - const handleRemoveImage = (id: string) => { - onChange(images.filter(img => img.id !== id)); - }; - - const handleReorder = (dragIndex: number, dropIndex: number) => { - const reorderedImages = [...images]; - const [draggedImage] = reorderedImages.splice(dragIndex, 1); - reorderedImages.splice(dropIndex, 0, draggedImage); - onChange(reorderedImages); + setImageUrl(''); // Очищаем после добавления }; return ( -
- {/* Add New Image */} -
-

Добавить фото

- -
+
+
+

Добавить фото

+ +
- {/* Gallery Preview */} -
-

Изображения галереи

- +
+

Изображения галереи

+ onEdit(img)} + onDelete={(id) => onDelete(id)} + onReorder={(dragIndex, dropIndex) => { + const reorderedImages = [...images]; + const [draggedImage] = reorderedImages.splice(dragIndex, 1); + reorderedImages.splice(dropIndex, 0, draggedImage); + onReorder(reorderedImages); + // setImages(reorderedImages); // Обновляем состояние изображений + }} + /> +
- - {/* Edit Image Modal */} - {editingImage && ( - setEditingImage(null)} - onSave={handleUpdateImage} - /> - )} -
); } \ No newline at end of file diff --git a/src/hooks/useGallery.ts b/src/hooks/useGallery.ts index 4e8835c..8700f6e 100644 --- a/src/hooks/useGallery.ts +++ b/src/hooks/useGallery.ts @@ -52,7 +52,7 @@ export function useGallery(articleId: string) { setImages(images.map(img => img.id === id ? updatedImage : img)); return updatedImage; } catch (err) { - console.error('Error updating image:', err); + console.error('Ошибка изменения изображения:', err); throw err; } }; @@ -62,7 +62,7 @@ export function useGallery(articleId: string) { await galleryService.deleteImage(id); setImages(images.filter(img => img.id !== id)); } catch (err) { - console.error('Error deleting image:', err); + console.error('Ошибка удаления изображения:', err); throw err; } }; @@ -75,7 +75,7 @@ export function useGallery(articleId: string) { ); setImages(reorderedImages); } catch (err) { - console.error('Error reordering images:', err); + console.error('Ошибка реорганизации изображений:', err); throw err; } }; diff --git a/src/pages/AdminPage.tsx b/src/pages/AdminPage.tsx index ce8dbcd..5cb98ad 100644 --- a/src/pages/AdminPage.tsx +++ b/src/pages/AdminPage.tsx @@ -1,23 +1,23 @@ import React, { useState, useEffect, useMemo } from 'react'; import axios from "axios"; +import MinutesWord from '../components/MinutesWord'; import { TipTapEditor } from '../components/TipTapEditor'; import { Header } from '../components/Header'; import { GalleryManager } from '../components/GalleryManager'; import { CoverImageUpload } from '../components/ImageUpload/CoverImageUpload'; import { ImageUploader } from '../components/ImageUpload/ImageUploader'; import { useGallery } from '../hooks/useGallery'; -import MinutesWord from '../components/MinutesWord'; -import { CategoryTitles, CityTitles, CategoryIds, CityIds, Article, Author } from '../types'; -import { Pencil, Trash2, ChevronLeft, ChevronRight, ImagePlus, X, ToggleLeft, ToggleRight} from 'lucide-react'; +import { CategoryTitles, CityTitles, CategoryIds, CityIds, Article, Author, GalleryImage } from '../types'; +import { Pencil, Trash2, ChevronLeft, ChevronRight, ImagePlus, X, ToggleLeft, ToggleRight } from 'lucide-react'; import { useAuthStore } from '../stores/authStore'; + const allCategoryIds: number[] = CategoryIds; const allCityIds: number[] = CityIds; // Обложка по умоланию для новых статей const DEFAULT_COVER_IMAGE = '/images/cover-placeholder.webp'; - export function AdminPage() { const { user } = useAuthStore(); const isAdmin = user?.permissions.isAdmin || false; @@ -44,19 +44,36 @@ export function AdminPage() { const [authors, setAuthors] = useState([]); const [authorId, setAuthorId] = useState(''); const [newImageUrl, setNewImageUrl] = useState(''); + const [displayedImages, setDisplayedImages] = useState([]); // Инициализация хука useGallery с текущим значением articleId (editingId) const { images: galleryImages, loading: galleryLoading, error: galleryError, -// addImage: addGalleryImage, -// updateImage: updateGalleryImage, -// deleteImage: deleteGalleryImage, + addImage: addGalleryImage, + updateImage: updateGalleryImage, + deleteImage: deleteGalleryImage, reorderImages: reorderGalleryImages, // refresh: refreshGallery } = useGallery(editingId || ''); + // Синхронизируем displayedImages с galleryImages при изменении galleryImages +/* + useEffect(() => { + setDisplayedImages(galleryImages); + }, [galleryImages]); +*/ + + // Добавляем useEffect для инициализации displayedImages при изменении editingId + useEffect(() => { + if (editingId) { + setDisplayedImages(galleryImages); + } else { + setDisplayedImages([]); // Очищаем, если editingId сбрасывается + } + }, [editingId, galleryImages]); // Зависимость от galleryImages нужна только для инициализации + // Загрузка списка авторов useEffect(() => { const fetchAuthors = async () => { @@ -291,25 +308,6 @@ export function AdminPage() { // Проверка прав пользователя const hasNoPermissions = availableCategoryIds.length === 0 || availableCityIds.length === 0; -/* - const handleGalleryImageUpload = async (imageUrl: string) => { - try { - await addGalleryImage({ - url: imageUrl, - caption: '', - alt: '', - width: 0, - height: 0, - size: 0, - format: 'webp' - }); - setShowGalleryUploader(false); - } catch { - setError('Failed to add gallery image'); - } - }; -*/ - // Show loading state while gallery is loading if (editingId && galleryLoading) { return ( @@ -478,11 +476,29 @@ export function AdminPage() { )}
{ - // Обработка реорганизации галереи через хук + setImageUrl={setNewImageUrl} + + onAddImage={async (imageData) => { + const newImage = await addGalleryImage(imageData); + setNewImageUrl(''); + setDisplayedImages((prev) => [...prev, newImage]); + }} + + onReorder={(images) => { reorderGalleryImages(images.map(img => img.id)); + setDisplayedImages(images); + }} + + onDelete={(id) => { + deleteGalleryImage(id); + setDisplayedImages((prev) => prev.filter(img => img.id !== id)); + }} + + onEdit={(image) => { + updateGalleryImage(image.id, image); + setDisplayedImages((prev) => prev.map(img => (img.id === image.id ? image : img))); }} /> @@ -505,6 +521,8 @@ export function AdminPage() { setReadTime(5); setAuthorId(authors[0].id || ''); setContent(''); + setDisplayedImages([]); // Очищаем отображаемые изображения + setNewImageUrl(''); // Очищаем URL нового изображения }} className="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" > diff --git a/src/types/index.ts b/src/types/index.ts index a8be4c7..e76d4a7 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -29,6 +29,11 @@ export interface GalleryImage { url: string; caption: string; alt: string; + width: number; + height: number; + size: number; + format: string; + } export interface Author {