fix(forms): enforce string field length limits globally

This commit is contained in:
Carlos (Almeira) 2026-06-22 14:33:06 -05:00
parent 827444d321
commit 74e0563349
3 changed files with 40 additions and 1 deletions

View File

@ -28,6 +28,8 @@ function extractCleanData(entity: string, formData: FormData): Record<string, an
const numericKeys = new Set(fields.filter(f => f.type === 'number').map(f => f.name));
const booleanKeys = new Set(fields.filter(f => f.type === 'boolean').map(f => f.name));
const textKeys = new Set(fields.filter(f => f.type === 'text' || f.type === 'url' || f.type === 'select').map(f => f.name));
const data: Record<string, any> = {};
for (const [key, value] of formData.entries()) {
@ -54,6 +56,12 @@ function extractCleanData(entity: string, formData: FormData): Record<string, an
// Omitir strings vacíos en campos opcionales para evitar errores de Appwrite
if (strVal === '' && !requiredKeys.has(key)) continue;
// Truncar genéricamente todos los campos de texto/url a 255 caracteres para prevenir desbordamientos
if (textKeys.has(key)) {
data[key] = strVal.substring(0, 255);
continue;
}
data[key] = strVal;
}
@ -62,6 +70,27 @@ function extractCleanData(entity: string, formData: FormData): Record<string, an
data.tipo = 'imagen';
}
// Enforce length constraints to prevent Appwrite validation errors
if (data.titulo && typeof data.titulo === 'string') {
data.titulo = data.titulo.substring(0, 250);
}
if (data.slug && typeof data.slug === 'string') {
data.slug = data.slug.substring(0, 100);
}
if (data.resumen_redes && typeof data.resumen_redes === 'string') {
data.resumen_redes = data.resumen_redes.substring(0, 500);
}
if (data.seo_titulo && typeof data.seo_titulo === 'string') {
data.seo_titulo = data.seo_titulo.substring(0, 60);
}
if (data.seo_descripcion && typeof data.seo_descripcion === 'string') {
data.seo_descripcion = data.seo_descripcion.substring(0, 160);
}
// Asegurar atributo requerido "tipo" para la colección posts
if (entity === 'posts' && !data.tipo) {
data.tipo = 'noticia';

View File

@ -239,6 +239,7 @@ export const EntityForm = ({
defaultValue={defaultValue}
onChange={(e) => setTitle(e.target.value)}
placeholder={`Nombre de ${field.label}...`}
maxLength={250}
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' ? (
@ -288,7 +289,14 @@ export const EntityForm = ({
<option value="false">No (Inactivo)</option>
</select>
) : (
<input type={field.type === 'number' ? 'number' : 'text'} name={field.name} defaultValue={defaultValue} required={field.required} className="w-full bg-slate-950 border border-slate-800 rounded-xl px-5 py-3 text-sm text-white focus:outline-none focus:border-cyan-500 transition-all" />
<input
type={field.type === 'number' ? 'number' : field.type === 'url' ? 'url' : 'text'}
name={field.name}
defaultValue={defaultValue}
required={field.required}
maxLength={field.type !== 'number' ? 255 : undefined}
className="w-full bg-slate-950 border border-slate-800 rounded-xl px-5 py-3 text-sm text-white focus:outline-none focus:border-cyan-500 transition-all"
/>
)}
</div>
);

View File

@ -240,6 +240,7 @@ export const PublicationLayout: React.FC<PublicationLayoutProps> = ({
onChange={(e) => setTitulo(e.target.value)}
placeholder="Escribe un título llamativo..."
required
maxLength={250}
className={inputClass}
/>
</FieldWrapper>
@ -259,6 +260,7 @@ export const PublicationLayout: React.FC<PublicationLayoutProps> = ({
onChange={(e) => { setSlug(e.target.value); setIsAutoSlug(false); }}
placeholder="url-de-la-publicacion"
required
maxLength={100}
className={`${inputClass} font-mono`}
/>
<button