Files

216 lines
7.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState } from "react";
import { Plus, Edit2, Trash2, X, Image as ImageIcon } from "lucide-react";
import { createGalleryImage, updateGalleryImage, deleteGalleryImage } from "@/app/actions/gallery";
import ImageUpload from "@/components/admin/ImageUpload";
type GalleryImage = {
id: string;
src: string;
alt: string | null;
order: number;
};
export default function GalleryClient({ initialImages }: { initialImages: GalleryImage[] }) {
const [images] = useState<GalleryImage[]>(initialImages);
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingImage, setEditingImage] = useState<GalleryImage | null>(null);
const [editingImageSrc, setEditingImageSrc] = useState<string>("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const openModal = (image?: GalleryImage) => {
setEditingImage(image || null);
setEditingImageSrc(image?.src || "");
setError(null);
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
setEditingImage(null);
setEditingImageSrc("");
setError(null);
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
setError(null);
const formData = new FormData(e.currentTarget);
let result;
if (editingImage) {
result = await updateGalleryImage(editingImage.id, formData);
} else {
result = await createGalleryImage(formData);
}
if (result.success) {
window.location.reload();
} else {
setError(result.error || "Bir hata oluştu");
setLoading(false);
}
};
const handleDelete = async (id: string) => {
if (!confirm("Bu görseli silmek istediğinize emin misiniz?")) return;
setLoading(true);
const result = await deleteGalleryImage(id);
if (result.success) {
window.location.reload();
} else {
alert(result.error || "Silinirken hata oluştu");
setLoading(false);
}
};
return (
<div className="p-8">
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-serif text-gray-900">Galeri Görselleri</h1>
<button
onClick={() => openModal()}
className="bg-turquoise text-white px-4 py-2 rounded-lg flex items-center gap-2 hover:bg-turquoise/90 transition-colors"
>
<Plus className="w-4 h-4" />
Yeni Görsel Ekle
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{images.map((image) => (
<div key={image.id} className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden group relative">
<div className="aspect-video w-full bg-gray-100 relative overflow-hidden">
{image.src ? (
<img
src={image.src}
alt={image.alt || "Galeri görseli"}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400">
<ImageIcon size={48} />
</div>
)}
</div>
<div className="p-4">
<div className="text-sm font-medium text-gray-900 truncate" title={image.alt || ""}>
{image.alt || <span className="text-gray-400 italic">Başlıksız</span>}
</div>
<div className="text-xs text-gray-500 mt-1">
Sıra: {image.order}
</div>
</div>
<div className="absolute top-2 right-2 flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity bg-white/90 backdrop-blur-sm p-1.5 rounded-lg shadow-sm">
<button
onClick={() => openModal(image)}
className="p-1.5 text-blue-600 hover:bg-blue-50 rounded transition-colors"
title="Düzenle"
>
<Edit2 className="w-4 h-4" />
</button>
<button
onClick={() => handleDelete(image.id)}
className="p-1.5 text-red-600 hover:bg-red-50 rounded transition-colors"
title="Sil"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
</div>
))}
{images.length === 0 && (
<div className="col-span-full p-12 text-center text-gray-500 bg-white rounded-xl border border-dashed border-gray-200">
<ImageIcon className="w-12 h-12 mx-auto text-gray-300 mb-3" />
<p>Henüz galeriye görsel eklenmemiş.</p>
</div>
)}
</div>
{/* Modal */}
{isModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 backdrop-blur-sm">
<div className="bg-white rounded-xl shadow-2xl max-w-lg w-full p-6 relative">
<button
onClick={closeModal}
className="absolute top-4 right-4 text-gray-400 hover:text-gray-600"
>
<X className="w-5 h-5" />
</button>
<h2 className="text-xl font-bold text-gray-900 mb-6">
{editingImage ? "Görseli Düzenle" : "Yeni Görsel Ekle"}
</h2>
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-lg text-sm mb-4">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Görsel Yükle</label>
<ImageUpload
name="src"
value={editingImageSrc}
onChange={setEditingImageSrc}
label="Galeri Görseli Yükle"
/>
<p className="text-xs text-gray-500 mt-1">Görsel bilgisayarınızdan veya kameradan seçilip yüklenebilir.</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Açıklama / Alt Metin</label>
<input
type="text"
name="alt"
defaultValue={editingImage?.alt || ""}
placeholder="Opsiyonel açıklama..."
className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-turquoise focus:border-transparent outline-none"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Sıralama (Opsiyonel)</label>
<input
type="number"
name="order"
defaultValue={editingImage?.order || 0}
className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-turquoise focus:border-transparent outline-none"
/>
<p className="text-xs text-gray-500 mt-1">Küçük numaralar ilk sırada gösterilir.</p>
</div>
<div className="pt-4 flex justify-end gap-3 border-t border-gray-100 mt-4">
<button
type="button"
onClick={closeModal}
className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
>
İptal
</button>
<button
type="submit"
disabled={loading}
className="bg-turquoise text-white px-6 py-2 rounded-lg hover:bg-turquoise/90 transition-colors disabled:opacity-50"
>
{loading ? "Kaydediliyor..." : "Kaydet"}
</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}