Files
mugladijitalmedya/app/admin/(dashboard)/projects/new/ProjectForm.tsx

208 lines
12 KiB
TypeScript
Raw 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, useEffect } from 'react';
import { createProjectAdmin, updateProjectAdmin } from '../../../actions';
import { Save, CheckCircle2, AlertCircle, X } from 'lucide-react';
import { useRouter } from 'next/navigation';
const slugify = (text: string) => {
return text
.toString()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.trim()
.replace(/\s+/g, '-')
.replace(/[^\w-]+/g, '')
.replace(/--+/g, '-');
};
export default function ProjectForm({
initialData,
services = [],
partners = []
}: {
initialData?: any,
services?: any[],
partners?: any[]
}) {
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
const [errorMsg, setErrorMsg] = useState('');
const [title, setTitle] = useState(initialData?.title || '');
const [slug, setSlug] = useState(initialData?.slug || '');
const router = useRouter();
// Auto-slug generation when title changes (only if it's a new project or manually changed title)
const handleTitleChange = (newTitle: string) => {
setTitle(newTitle);
if (!initialData) {
setSlug(slugify(newTitle));
}
};
const parseSafe = (data: any) => {
let current = data;
try {
for (let i = 0; i < 3; i++) {
if (typeof current === 'string' && (current.trim().startsWith('[') || current.trim().startsWith('"'))) {
current = JSON.parse(current);
} else {
break;
}
}
return Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
} catch (e) {
return Array.isArray(current) ? current : (typeof current === 'string' && current ? [current] : []);
}
};
const initialTechStack = parseSafe(initialData?.tech_stack);
const initialGallery = parseSafe(initialData?.gallery);
const initialCategories = parseSafe(initialData?.category);
async function handleSubmit(formData: FormData) {
setStatus('loading');
let res;
if (initialData?.id) {
res = await updateProjectAdmin(initialData.id, formData);
} else {
res = await createProjectAdmin(formData);
}
if (res.error) {
setErrorMsg(res.error);
setStatus('error');
} else {
setStatus('success');
setTimeout(() => {
router.push('/admin/projects');
router.refresh();
}, 1000);
}
}
return (
<form action={handleSubmit} className="bg-zinc-950 border border-white/10 rounded-3xl p-8 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Proje Adı (Partner Seçin)</label>
<select
name="title"
required
value={title}
onChange={(e) => handleTitleChange(e.target.value)}
className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none"
>
<option value="" className="bg-zinc-900">Seçiniz...</option>
{partners.map(p => (
<option key={p.id} value={p.name} className="bg-zinc-900">{p.name}</option>
))}
</select>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Kısa Başlık (URL Slug)</label>
<input
type="text"
name="slug"
value={slug}
onChange={(e) => setSlug(e.target.value)}
required
className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none font-mono text-xs"
placeholder="örn: marka-ismi"
/>
</div>
<div className="space-y-2 lg:col-span-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Kategoriler (Hizmetler - Çoklu Seçim)</label>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 p-4 bg-white/5 border border-white/10 rounded-xl">
{services.map(s => {
const isChecked = initialCategories.includes(s.title);
return (
<label key={s.id} className="flex items-center gap-3 cursor-pointer group">
<input
type="checkbox"
name="category"
value={s.title}
defaultChecked={isChecked}
className="w-4 h-4 rounded border-white/10 bg-white/5 accent-[#1e9a83]"
/>
<span className="text-[11px] font-bold uppercase text-white/60 group-hover:text-white transition-colors">
{s.title}
</span>
</label>
);
})}
</div>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Yıl</label>
<input type="text" name="year" defaultValue={initialData?.year || new Date().getFullYear()} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="Örn: 2024" />
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Müşteri (Görünen İsim)</label>
<input type="text" name="client" defaultValue={initialData?.client || title} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="Örn: ABC A.Ş." />
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Lokasyon</label>
<input type="text" name="location" defaultValue={initialData?.location || 'Muğla, TR'} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="Örn: Muğla, TR" />
</div>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Alt Başlık (Kısa ıklama)</label>
<input type="text" name="subtitle" defaultValue={initialData?.subtitle} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="Projenin kısa özeti..." />
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Ana Görsel (URL veya Yol)</label>
<input type="text" name="hero_image" defaultValue={initialData?.hero_image} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="/images/projects/1.jpg" />
</div>
<h3 className="text-sm font-bold uppercase tracking-widest text-white/60 mt-8 mb-4 border-b border-white/10 pb-2">Hikaye & Detay</h3>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Hikaye Başlığı</label>
<input type="text" name="narrative_title" defaultValue={initialData?.narrative_title} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none" placeholder="Geleceği Yeniden Şekillendirmek" />
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Hikaye İçeriği (Paragraf)</label>
<textarea name="narrative_desc" defaultValue={initialData?.narrative_desc} rows={4} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none resize-none" placeholder="Projenin detaylııklaması..."></textarea>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Teknolojiler (Her satıra bir tane)</label>
<textarea name="tech_stack" defaultValue={initialTechStack.join('\n')} rows={5} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none resize-none" placeholder="React&#10;Next.js&#10;TailwindCSS"></textarea>
</div>
<div className="space-y-2">
<label className="text-[10px] font-bold uppercase tracking-widest text-white/40 ml-1">Galeri & Instagram Linkleri (Her satıra bir tane)</label>
<textarea name="gallery" defaultValue={initialGallery.join('\n')} rows={5} className="w-full bg-white/5 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-[#1e9a83] outline-none resize-none" placeholder="https://instagram.com/p/...&#10;/img1.jpg&#10;/img2.jpg"></textarea>
</div>
</div>
<div className="flex items-center gap-3 pt-2">
<input type="checkbox" name="is_featured" id="is_featured" defaultChecked={initialData?.is_featured} className="w-5 h-5 accent-[#1e9a83] rounded" />
<label htmlFor="is_featured" className="text-sm font-bold text-white/80 cursor-pointer">Bu projeyi anasayfada (Öne Çıkanlar) göster</label>
</div>
<div className="pt-6">
<button type="submit" disabled={status === 'loading'} className="bg-[#1e9a83] hover:bg-[#157a67] text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 disabled:opacity-50">
<Save className="w-5 h-5" />
{status === 'loading' ? 'Kaydediliyor...' : initialData ? 'Projeyi Güncelle' : 'Projeyi Kaydet'}
</button>
</div>
{status === 'success' && (
<div className="flex items-center gap-2 text-green-500 text-sm font-bold bg-green-500/10 p-4 rounded-xl mt-4">
<CheckCircle2 className="w-5 h-5" /> Proje başarıyla {initialData ? 'güncellendi' : 'eklendi'}! Yönlendiriliyorsunuz...
</div>
)}
{status === 'error' && (
<div className="flex items-center gap-2 text-red-500 text-sm font-bold bg-red-500/10 p-4 rounded-xl mt-4">
<AlertCircle className="w-5 h-5" /> {errorMsg}
</div>
)}
</form>
);
}