"use client"; import { useRef, useState, useEffect } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useToast } from '@/contexts/ToastContext'; type UploadedImage = { url: string; path: string; name: string; }; const CATEGORY_OPTIONS = [ { value: 'Engenharia Veicular', label: 'Engenharia Veicular' }, { value: 'Projetos Mecânicos', label: 'Projetos Mecânicos' }, { value: 'Laudos e Inspeções', label: 'Laudos e Inspeções' }, { value: 'Segurança do Trabalho', label: 'Segurança do Trabalho' }, ]; const STATUS_OPTIONS = [ { value: 'Concluído', label: 'Concluído' }, { value: 'Em andamento', label: 'Em andamento' }, { value: 'Rascunho', label: 'Rascunho' }, ]; export default function EditProject({ params }: { params: { id: string } }) { const router = useRouter(); const { success, error } = useToast(); const coverInputRef = useRef(null); const galleryInputRef = useRef(null); const [loadingData, setLoadingData] = useState(true); const [loading, setLoading] = useState(false); const [categories, setCategories] = useState(CATEGORY_OPTIONS); const [newCategory, setNewCategory] = useState(''); const [formData, setFormData] = useState({ title: '', category: '', client: '', status: 'Concluído', description: '', date: '', featured: false, }); const [coverImage, setCoverImage] = useState(null); const [galleryImages, setGalleryImages] = useState([]); const [uploadingCover, setUploadingCover] = useState(false); const [uploadingGallery, setUploadingGallery] = useState(false); const isSaving = loading || uploadingCover || uploadingGallery; // Carregar dados do projeto useEffect(() => { async function fetchProject() { try { const res = await fetch(`/api/projects/${params.id}`); if (!res.ok) { throw new Error('Projeto não encontrado'); } const project = await res.json(); setFormData({ title: project.title || '', category: project.category || '', client: project.client || '', status: project.status || 'Concluído', description: project.description || '', date: project.completionDate ? project.completionDate.split('T')[0] : '', featured: project.featured || false, }); if (project.coverImage) { setCoverImage({ url: project.coverImage, path: project.coverImage, name: 'Imagem de capa', }); } if (project.galleryImages && project.galleryImages.length > 0) { setGalleryImages( project.galleryImages.map((url: string, index: number) => ({ url, path: url, name: `Imagem ${index + 1}`, })) ); } } catch (err) { console.error('Erro ao carregar projeto:', err); error('Não foi possível carregar o projeto.'); router.push('/admin/projetos'); } finally { setLoadingData(false); } } fetchProject(); }, [params.id, error, router]); const uploadFile = async (file: File): Promise => { if (file.size > 2 * 1024 * 1024) { error('Arquivo maior que 2MB. Escolha uma imagem menor.'); return null; } const supportedTypes = ['image/png', 'image/jpeg', 'image/webp']; if (!supportedTypes.includes(file.type)) { error('Formato inválido. Utilize PNG, JPG ou WEBP.'); return null; } const body = new FormData(); body.append('file', file); const response = await fetch('/api/upload', { method: 'POST', body, }); if (!response.ok) { const data = await response.json().catch(() => ({})); throw new Error(data?.error || 'Erro ao enviar imagem'); } const data = await response.json(); return { url: data.url, path: data.path, name: file.name, }; }; const handleCoverSelect = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; setUploadingCover(true); try { const uploaded = await uploadFile(file); if (uploaded) { setCoverImage(uploaded); success('Imagem de capa carregada.'); } } catch (err) { console.error('Erro ao enviar imagem de capa:', err); error(err instanceof Error ? err.message : 'Falha ao enviar imagem de capa.'); } finally { setUploadingCover(false); event.target.value = ''; } }; const handleGallerySelect = async (event: React.ChangeEvent) => { const files = Array.from(event.target.files ?? []); if (files.length === 0) return; if (galleryImages.length + files.length > 8) { error('Limite de 8 imagens atingido. Remova algumas antes de adicionar novas.'); event.target.value = ''; return; } setUploadingGallery(true); try { for (const file of files) { const uploaded = await uploadFile(file); if (uploaded) { setGalleryImages((prev) => [...prev, uploaded]); } } success('Galeria atualizada.'); } catch (err) { console.error('Erro ao enviar imagem da galeria:', err); error(err instanceof Error ? err.message : 'Falha ao enviar imagem da galeria.'); } finally { setUploadingGallery(false); event.target.value = ''; } }; const handleRemoveGalleryImage = (path: string) => { setGalleryImages((prev) => prev.filter((image) => image.path !== path)); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.title || !formData.category) { error('Informe ao menos o título e a categoria do projeto.'); return; } setLoading(true); try { const response = await fetch(`/api/projects/${params.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: formData.title.trim(), category: formData.category, client: formData.client?.trim() || null, status: formData.status, description: formData.description?.trim() || null, completionDate: formData.date ? new Date(formData.date).toISOString() : null, coverImage: coverImage?.url ?? null, galleryImages: galleryImages.map((image) => image.url), featured: formData.featured, }), }); const data = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(data?.error || 'Erro ao atualizar projeto'); } success('Projeto atualizado com sucesso!'); router.push('/admin/projetos'); } catch (err) { console.error('Erro ao atualizar projeto:', err); error(err instanceof Error ? err.message : 'Não foi possível atualizar o projeto.'); } finally { setLoading(false); } }; if (loadingData) { return (
); } return (

Editar Projeto

Atualize as informações do projeto.

{/* Basic Info */}

Informações Básicas

setFormData({...formData, title: e.target.value})} className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all" placeholder="Ex: Adequação de Frota Coca-Cola" required />

Não encontra a categoria? Adicione uma nova abaixo

setNewCategory(e.target.value)} className="flex-1 px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all" placeholder="Ex: Consultoria Ambiental" />
setFormData({...formData, client: e.target.value})} className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all" placeholder="Ex: Coca-Cola FEMSA" />
setFormData({...formData, date: e.target.value})} className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all" />

Projetos em destaque podem ser exibidos em seções especiais como a home.

{/* Media */}

Mídia

coverInputRef.current?.click()} className="border-2 border-dashed border-gray-300 dark:border-white/20 rounded-xl p-6 text-center hover:border-primary dark:hover:border-primary transition-colors cursor-pointer bg-gray-50 dark:bg-white/5 relative min-h-[200px] flex items-center justify-center" > {coverImage ? (
{coverImage.name}
) : (
{uploadingCover ? ( ) : ( )}

{uploadingCover ? 'Enviando imagem...' : 'Clique para fazer upload ou arraste e solte'}

PNG, JPG ou WEBP (máximo 2MB)

)}
{galleryImages.map((image) => (
{image.name}
))}

Adicione até 8 imagens para apresentar detalhes do projeto.

{/* Actions */}
Cancelar
); }