fix: resolve production UnrecognizedActionError by externalizing entity server actions into stable top-level exports

This commit is contained in:
Carlos (Almeira) 2026-03-27 18:42:07 -05:00
parent 64c6568a99
commit 44947d0d29
3 changed files with 79 additions and 52 deletions

View File

@ -0,0 +1,73 @@
'use server';
import { collectionMap, SCHEMA_MAP } from '@/lib/schema';
import { createDocumentServer, updateDocumentServer } from './appwrite';
import { redirect } from 'next/navigation';
/**
* Centralized action to create a new entity document
*/
export async function saveEntityAction(entity: string, formData: FormData) {
const collectionId = collectionMap[entity];
const fields = SCHEMA_MAP[entity] || [];
if (!collectionId) throw new Error(`Colección no encontrada para ${entity}`);
const data: Record<string, any> = {};
for (const [key, value] of formData.entries()) {
if (key.startsWith('$ACTION')) continue;
data[key] = value;
}
// Type conversions based on schema
const numericFields = fields.filter(f => f.type === 'number').map(f => f.name);
for (const nKey of numericFields) {
if (data[nKey]) data[nKey] = parseFloat(data[nKey]);
}
// Normalization
if (data.estado && typeof data.estado === 'string') {
data.estado = data.estado.toLowerCase();
}
const res = await createDocumentServer(collectionId, data);
if (res.success) {
redirect(`/dashboard/${entity}`);
} else {
throw new Error(res.error || "Error desconocido al crear documento");
}
}
/**
* Centralized action to update an existing entity document
*/
export async function updateEntityAction(entity: string, id: string, formData: FormData) {
const collectionId = collectionMap[entity];
const fields = SCHEMA_MAP[entity] || [];
if (!collectionId) throw new Error(`Colección no encontrada para ${entity}`);
const data: Record<string, any> = {};
for (const [key, value] of formData.entries()) {
if (key.startsWith('$ACTION')) continue;
data[key] = value;
}
// Type conversions based on schema
const numericFields = fields.filter(f => f.type === 'number').map(f => f.name);
for (const nKey of numericFields) {
if (data[nKey]) data[nKey] = parseFloat(data[nKey]);
}
// Normalization
if (data.estado && typeof data.estado === 'string') {
data.estado = data.estado.toLowerCase();
}
const res = await updateDocumentServer(collectionId, id, data);
if (res.success) {
redirect(`/dashboard/${entity}`);
} else {
throw new Error(res.error || "Error desconocido al actualizar documento");
}
}

View File

@ -2,6 +2,7 @@ import { APPWRITE_ALMEIRA_CONFIG, projectId, endpoint } from '@/lib/appwrite';
import { createSessionClient } from '@/lib/appwrite.server';
import { collectionMap, SCHEMA_MAP } from '@/lib/schema';
import { updateDocumentServer } from '@/app/actions/appwrite';
import { updateEntityAction } from '@/app/actions/entities';
import { redirect } from 'next/navigation';
import { EntityForm } from '@/components/dashboard/EntityForm';
@ -58,31 +59,7 @@ export default async function EditEntityPage({ params }: { params: Promise<{ ent
})
);
async function updateAction(formData: FormData) {
'use server';
const data: Record<string, any> = {};
for (const [key, value] of formData.entries()) {
if (key.startsWith('$ACTION')) continue;
data[key] = value;
}
const numericFields = fields.filter(f => f.type === 'number').map(f => f.name);
for (const nKey of numericFields) {
if(data[nKey]) data[nKey] = parseFloat(data[nKey]);
}
if (data.estado && typeof data.estado === 'string') {
data.estado = data.estado.toLowerCase();
}
const res = await updateDocumentServer(collectionId, id, data);
if(res.success) {
redirect(`/dashboard/${entity}`);
} else {
console.error("Server Action res error", res.error);
}
}
const boundUpdate = updateEntityAction.bind(null, entity, id);
return (
<EntityForm
@ -91,7 +68,7 @@ export default async function EditEntityPage({ params }: { params: Promise<{ ent
initialData={document}
fields={fields}
relationData={relationData}
submitAction={updateAction}
submitAction={boundUpdate}
appwriteConfig={{ endpoint, projectId }}
/>
);

View File

@ -2,6 +2,7 @@ import { APPWRITE_ALMEIRA_CONFIG, projectId, endpoint } from '@/lib/appwrite';
import { createSessionClient } from '@/lib/appwrite.server';
import { collectionMap, SCHEMA_MAP } from '@/lib/schema';
import { createDocumentServer } from '@/app/actions/appwrite';
import { saveEntityAction } from '@/app/actions/entities';
import { redirect } from 'next/navigation';
import { EntityForm } from '@/components/dashboard/EntityForm';
@ -41,31 +42,7 @@ export default async function NewEntityPage({ params }: { params: Promise<{ enti
})
);
async function submitAction(formData: FormData) {
'use server';
const data: Record<string, any> = {};
for (const [key, value] of formData.entries()) {
if (key.startsWith('$ACTION')) continue;
data[key] = value;
}
const numericFields = fields.filter(f => f.type === 'number').map(f => f.name);
for (const nKey of numericFields) {
if(data[nKey]) data[nKey] = parseFloat(data[nKey]);
}
if (data.estado && typeof data.estado === 'string') {
data.estado = data.estado.toLowerCase();
}
const res = await createDocumentServer(collectionId, data);
if(res.success) {
redirect(`/dashboard/${entity}`);
} else {
console.error("Server Action res error", res.error);
}
}
const boundSave = saveEntityAction.bind(null, entity);
return (
<EntityForm
@ -73,7 +50,7 @@ export default async function NewEntityPage({ params }: { params: Promise<{ enti
entityName={entityName}
fields={fields}
relationData={relationData}
submitAction={submitAction}
submitAction={boundSave}
appwriteConfig={{ endpoint, projectId }}
/>
);