'use client'; /** * NOVA CMS - DYNAMIC CONTENT FORM * ================================ * * Formulario dinámico profesional con diseño iOS para crear/editar contenido. * Cada campo se presenta como una tarjeta individual con diseño elegante. */ import { useForm, FormProvider } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Switch } from '@/components/ui/switch'; import { FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'; import { useToast } from '@/hooks/use-toast'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { ChevronsUpDown, Save, FileText, Calendar, Hash, ToggleRight, Image } from 'lucide-react'; import { cn } from '@/lib/utils'; // Types para el contenido dinámico interface Field { id: string; label: string; apiIdentifier: string; type: 'TEXT' | 'RICH_TEXT' | 'NUMBER' | 'BOOLEAN' | 'DATE' | 'MEDIA'; isRequired: boolean; } interface ContentType { id: string; name: string; apiIdentifier: string; description?: string; fields: Field[]; } interface DynamicContentFormProps { contentType: ContentType; initialData?: Record; entryId?: string; mode?: 'create' | 'edit'; onSave?: (data: Record) => Promise; } // Generador de schema dinámico basado en fields function generateDynamicSchema(fields: Field[]) { const schemaShape: Record = {}; fields.forEach(field => { let fieldValidator; switch (field.type) { case 'TEXT': case 'RICH_TEXT': case 'MEDIA': fieldValidator = z.string(); if (field.isRequired) { fieldValidator = fieldValidator.min(1, `${field.label} es requerido`); } break; case 'NUMBER': fieldValidator = z.number(); if (field.isRequired) { fieldValidator = fieldValidator.min(0, `${field.label} debe ser un número válido`); } break; case 'BOOLEAN': fieldValidator = z.boolean(); break; case 'DATE': fieldValidator = z.string(); if (field.isRequired) { fieldValidator = fieldValidator.min(1, `${field.label} es requerido`); } break; default: fieldValidator = z.string(); } if (!field.isRequired) { fieldValidator = fieldValidator.optional(); } schemaShape[field.apiIdentifier] = fieldValidator; }); return z.object(schemaShape); } // Componente para renderizar un campo individual con diseño de formulario profesional function DynamicField({ field, control }: { field: Field; control: any }) { const getFieldIcon = (type: Field['type']) => { switch (type) { case 'TEXT': return ; case 'RICH_TEXT': return ; case 'NUMBER': return ; case 'BOOLEAN': return ; case 'DATE': return ; case 'MEDIA': return ; default: return ; } }; const getFieldDescription = (type: Field['type']) => { switch (type) { case 'TEXT': return 'Texto simple de una línea'; case 'RICH_TEXT': return 'Texto con formato y múltiples líneas'; case 'NUMBER': return 'Valores numéricos y decimales'; case 'BOOLEAN': return 'Opción verdadero/falso (sí/no)'; case 'DATE': return 'Fechas y horarios'; case 'MEDIA': return 'URLs de imágenes y archivos'; default: return 'Campo de contenido'; } }; return ( (
{/* Header elegante del campo */}
{getFieldIcon(field.type)}
{field.label} {field.isRequired && ( Obligatorio )}

{getFieldDescription(field.type)}

{/* Contenido del campo */}
{field.type === 'TEXT' && (
)} {field.type === 'RICH_TEXT' && (