almeira-web/src/app/dashboard/[entity]/new/page.tsx
Carlos (Almeira) dda9ae0f4a feat: implement robust publications module with real-time validation and state management
- Refactor dashboard entity pages to support dynamic publications management.
- Add Publications Module with Atomic Design components (PostCard, PublicationsList, FormSection).
- Implement Zod-based real-time validation for publication forms.
- Manage state using Zustand for optimistic UI and in-place relations.
- Add RBAC protection with PermissionGuard and server-side API validation.
- Fix: Resolve TypeScript type error in AdWrappers.tsx to ensure successful build.
- Add ToastProvider and ErrorBoundary for improved user experience.
- Update dependencies for publications logic.
2026-03-28 08:47:40 -05:00

103 lines
3.3 KiB
TypeScript

import { APPWRITE_ALMEIRA_CONFIG, projectId, endpoint } from '@/lib/appwrite';
import { createAdminClient, getLoggedInUser } from '@/lib/appwrite.server';
import { Query } from 'node-appwrite';
import { collectionMap, SCHEMA_MAP } from '@/lib/schema';
import { saveEntityAction } from '@/app/actions/entities';
import { redirect } from 'next/navigation';
import type { AuthUser } from '@/types/publications';
/**
* New entity page — uses the specialized PublicationLayout for 'posts',
* and the generic EntityForm for all other entity types.
*/
export default async function NewEntityPage({
params,
}: {
params: Promise<{ entity: string }>;
}) {
const { entity } = await params;
const collectionId = collectionMap[entity];
const fields = SCHEMA_MAP[entity] || [];
if (!collectionId || fields.length === 0) {
return (
<div className="p-8">
<h1 className="text-red-500 font-bold text-xl">Configuración no encontrada para: {entity}</h1>
</div>
);
}
// Auth check
const user = await getLoggedInUser();
if (!user) redirect('/login');
// Pre-load all relation data server-side
const relationData: Record<string, Array<{ $id: string; [key: string]: unknown }>> = {};
try {
const client = await createAdminClient();
await Promise.all(
fields
.filter((f) => f.type === 'relation' && f.relationCollection)
.map(async (field) => {
const relKey = field.relationCollection as string;
const relColId = collectionMap[relKey];
if (!relColId) return;
try {
const res = await client.databases.listDocuments(
APPWRITE_ALMEIRA_CONFIG.databaseId,
relColId,
[Query.limit(100)]
);
relationData[field.name] = res.documents as Array<{ $id: string; [key: string]: unknown }>;
} catch {
// Silent fail for individual relations
}
})
);
} catch (error) {
console.error('Error loading relation data:', error);
}
const boundSave = saveEntityAction.bind(null, entity);
const appwriteConfig = {
endpoint,
projectId,
databaseId: APPWRITE_ALMEIRA_CONFIG.databaseId,
};
// ── POSTS: Use the new PublicationLayout ──────────────
if (entity === 'posts') {
const { default: PublicationLayout } = await import('@/components/publications/PublicationLayout');
return (
<PublicationLayout
user={user as AuthUser}
relationData={relationData}
submitAction={boundSave}
appwriteConfig={appwriteConfig}
/>
);
}
// ── OTHER ENTITIES: Use the generic EntityForm ────────
const { EntityForm } = await import('@/components/dashboard/EntityForm');
const entityNames: Record<string, string> = {
categories: 'Categorías', clients: 'Clientes', client_types: 'Tipos de Cliente',
countries: 'Países', departments: 'Departamentos', cities: 'Ciudades',
contracts: 'Contratos', payment_methods: 'Formas de Pago', publication_types: 'Tipos de Publicación',
};
return (
<EntityForm
entity={entity}
entityName={entityNames[entity] || entity.replace(/_/g, ' ')}
fields={fields}
relationData={relationData}
submitAction={boundSave}
appwriteConfig={{ endpoint, projectId }}
/>
);
}