- 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.
103 lines
3.3 KiB
TypeScript
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 }}
|
|
/>
|
|
);
|
|
}
|