'use client'; import { useState, useEffect, useTransition } from 'react'; import { useRouter } from 'next/navigation'; import { ArrowLeft, Save, Globe, Calendar, Tag, Image as ImageIcon, Eye, Code } from 'lucide-react'; import Link from 'next/link'; import { FieldDefinition } from '@/lib/schema'; import { MediaPickerMini } from './MediaPickerMini'; import { RichTextEditor } from './RichTextEditor'; import { QuickCreateModal } from './QuickCreateModal'; import { collectionMap } from '@/lib/schema'; import { Client, Databases } from 'appwrite'; // Minimalistic image preview for relations with 'media' const MediaPreview = ({ fileId, bucketId, endpoint, projectId }: any) => { if(!fileId) return null; const url = `${endpoint}/storage/buckets/${bucketId}/files/${fileId}/view?project=${projectId}`; return (
// eslint-disable-next-line @next/next/no-img-element Preview
Imagen Seleccionada
); } interface EntityFormProps { entity: string; entityName: string; initialData?: any; fields: FieldDefinition[]; relationData: Record; submitAction: (formData: FormData) => Promise; appwriteConfig: { endpoint: string; projectId: string; } } export const EntityForm = ({ entity, entityName, initialData, fields, relationData, submitAction, appwriteConfig }: EntityFormProps) => { const router = useRouter(); const [isPending, startTransition] = useTransition(); const [title, setTitle] = useState(initialData?.titulo || initialData?.nombre || ''); const [slug, setSlug] = useState(initialData?.slug || ''); const [isAutoSlug, setIsAutoSlug] = useState(!initialData?.slug); const [featuredImageId, setFeaturedImageId] = useState(initialData?.imagen_destacada_id || ''); const [editorValues, setEditorValues] = useState>({}); const [localRelationData, setLocalRelationData] = useState(relationData); const [activeTab, setActiveTab] = useState(''); const [isModalOpen, setIsModalOpen] = useState(false); const [modalEntity, setModalEntity] = useState(''); const [activeRelationField, setActiveRelationField] = useState(''); // Initialize editor values useEffect(() => { const initialValues: Record = {}; fields.forEach(f => { if (f.type === 'textarea') { initialValues[f.name] = initialData?.[f.name] || ''; } }); setEditorValues(initialValues); }, [fields, initialData]); // Update slug automatically if auto-slug is enabled useEffect(() => { if (isAutoSlug) { const generated = title .toLowerCase() .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, ''); setSlug(generated); } }, [title, isAutoSlug]); const sections = Array.from(new Set(fields.map(f => f.section || 'General'))); useEffect(() => { if (sections.length > 0 && !activeTab) { setActiveTab(sections[0]); } }, [sections, activeTab]); const refreshRelation = async (field: string, collectionId: string) => { const client = new Client() .setEndpoint(appwriteConfig.endpoint) .setProject(appwriteConfig.projectId); const databases = new Databases(client); try { const res = await databases.listDocuments('almeira', collectionId, []); setLocalRelationData(prev => ({ ...prev, [field]: res.documents })); } catch (err) { console.error("Error al refrescar relación:", err); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); // Add editor values to formData for (const [key, value] of Object.entries(editorValues)) { formData.set(key, value); } // Ensure featured image ID is set if present if (featuredImageId) { formData.set('imagen_destacada_id', featuredImageId); } startTransition(async () => { await submitAction(formData); }); }; // Organize fields into Main Content and Sidebar Metadata const sidebarFieldNames = ['estado', 'fecha_publicacion', 'fecha_finalizacion', 'slug', 'imagen_destacada_id', 'categoria_id', 'tipo_publicacion_id']; const mainFields = fields.filter(f => !sidebarFieldNames.includes(f.name)); const sidebarFields = fields.filter(f => sidebarFieldNames.includes(f.name)); const getDefValue = (field: FieldDefinition) => { const val = initialData ? initialData[field.name] : null; // Set smart defaults for new items if (!initialData) { if (field.name === 'estado') return 'borrador'; if (field.name === 'fecha_publicacion' || field.type === 'date') { // Get local ISO string for datetime-local input const now = new Date(); return new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().slice(0, 16); } if (field.type === 'boolean') return 'false'; } if (val === undefined || val === null) return ''; if (field.type === 'boolean') return val ? 'true' : 'false'; if (field.type === 'date') return new Date(val).toISOString().slice(0, 16); if (field.type === 'relation') return typeof val === 'object' ? val.$id : val; return val; }; return ( <>
{/* Header Sticky */}

{initialData ? 'Editando' : 'Nuevo'}: {entityName}

{initialData &&

{initialData.$id}

}
{sections.map(section => ( ))}
{fields.filter(f => (f.section || 'General') === activeTab).map(field => { const defaultValue = getDefValue(field); const gridSpanMap: Record = { 1: 'col-span-1', 2: 'col-span-2', 3: 'col-span-3', 4: 'col-span-4', 5: 'col-span-5', 6: 'col-span-6', 7: 'col-span-7', 8: 'col-span-8', 9: 'col-span-9', 10: 'col-span-10', 11: 'col-span-11', 12: 'col-span-12' }; const gridSpan = gridSpanMap[field.gridSize || 12] || 'col-span-12'; return (
{field.type === 'relation' && ( Double click to create quick + )}
{field.name === 'titulo' || field.name === 'nombre_entidad' ? ( setTitle(e.target.value)} placeholder={`Nombre de ${field.label}...`} className="w-full bg-transparent border-b-2 border-slate-800 py-2 text-2xl font-bold text-white focus:outline-none focus:border-cyan-500 transition-all placeholder:text-slate-700" /> ) : field.type === 'textarea' ? ( setEditorValues(prev => ({ ...prev, [field.name]: val }))} /> ) : field.type === 'relation' ? (
{field.relationCollection === 'media' && ( )}
) : field.type === 'select' ? ( ) : field.type === 'date' ? ( ) : field.type === 'boolean' ? ( ) : ( )}
); })}
setIsModalOpen(false)} onSuccess={async (newId) => { const relField = fields.find(f => f.name === activeRelationField); if (relField?.relationCollection) { await refreshRelation(activeRelationField, collectionMap[relField.relationCollection]); // Set wait to ensure state has updated options before selecting setTimeout(() => { const selectElement = document.querySelector(`select[name="${activeRelationField}"]`) as HTMLSelectElement; if (selectElement) { selectElement.value = newId; } }, 1000); } }} /> ); };