Доработка работы с галереей. Работает добавление и изменение порядка изображений. Не работает редактирование.
This commit is contained in:
parent
9ba64a453c
commit
dc00bca390
@ -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<GalleryImage, 'id'>) => void;
|
||||
onReorder: (images: GalleryImage[]) => void;
|
||||
onDelete: (id: string) => void;
|
||||
onEdit: (image: GalleryImage) => void;
|
||||
}
|
||||
|
||||
export function GalleryManager({ images, imageUrl, onChange }: GalleryManagerProps) {
|
||||
const [editingImage, setEditingImage] = useState<GalleryImage | null>(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 (
|
||||
<div className="space-y-6">
|
||||
{/* Add New Image */}
|
||||
<div className="border rounded-lg p-4 space-y-4">
|
||||
<h3 className="text-lg font-medium text-gray-900">Добавить фото</h3>
|
||||
<ImageForm
|
||||
url={newImageUrl}
|
||||
caption={newImageCaption}
|
||||
alt={newImageAlt}
|
||||
onUrlChange={setNewImageUrl}
|
||||
onCaptionChange={setNewImageCaption}
|
||||
onAltChange={setNewImageAlt}
|
||||
onSubmit={handleAddImage}
|
||||
submitLabel="Добавить в галерею"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<div className="border rounded-lg p-4 space-y-4">
|
||||
<h3 className="text-lg font-medium text-gray-900">Добавить фото</h3>
|
||||
<ImageForm
|
||||
url={newImageUrl}
|
||||
caption={newImageCaption}
|
||||
alt={newImageAlt}
|
||||
onUrlChange={setNewImageUrl}
|
||||
onCaptionChange={setNewImageCaption}
|
||||
onAltChange={setNewImageAlt}
|
||||
onSubmit={handleAddImage}
|
||||
submitLabel="Добавить в галерею"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Gallery Preview */}
|
||||
<div className="border rounded-lg p-4">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Изображения галереи</h3>
|
||||
<GalleryGrid
|
||||
images={images}
|
||||
onEdit={setEditingImage}
|
||||
onDelete={handleRemoveImage}
|
||||
onReorder={handleReorder}
|
||||
/>
|
||||
<div className="border rounded-lg p-4">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">Изображения галереи</h3>
|
||||
<GalleryGrid
|
||||
images={images}
|
||||
onEdit={(img) => 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); // Обновляем состояние изображений
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Edit Image Modal */}
|
||||
{editingImage && (
|
||||
<EditImageModal
|
||||
image={editingImage}
|
||||
onClose={() => setEditingImage(null)}
|
||||
onSave={handleUpdateImage}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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<Author[]>([]);
|
||||
const [authorId, setAuthorId] = useState<string>('');
|
||||
const [newImageUrl, setNewImageUrl] = useState('');
|
||||
const [displayedImages, setDisplayedImages] = useState<GalleryImage[]>([]);
|
||||
|
||||
// Инициализация хука 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() {
|
||||
)}
|
||||
</div>
|
||||
<GalleryManager
|
||||
images={galleryImages}
|
||||
images={displayedImages} // Используем displayedImages вместо galleryImages
|
||||
imageUrl={newImageUrl}
|
||||
onChange={(images) => {
|
||||
// Обработка реорганизации галереи через хук
|
||||
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)));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@ -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"
|
||||
>
|
||||
|
@ -29,6 +29,11 @@ export interface GalleryImage {
|
||||
url: string;
|
||||
caption: string;
|
||||
alt: string;
|
||||
width: number;
|
||||
height: number;
|
||||
size: number;
|
||||
format: string;
|
||||
|
||||
}
|
||||
|
||||
export interface Author {
|
||||
|
Loading…
x
Reference in New Issue
Block a user