220 lines
7.4 KiB
TypeScript
220 lines
7.4 KiB
TypeScript
/**
|
||
* @file publications.ts
|
||
* @description Strict TypeScript interfaces and types for the Publications module.
|
||
* All entities, props, and enums are defined here to enforce type safety across
|
||
* the entire publications feature.
|
||
*/
|
||
|
||
// ─────────────────────────────────────────────
|
||
// ENUMS
|
||
// ─────────────────────────────────────────────
|
||
|
||
/** Roles de usuario para el sistema RBAC */
|
||
export type UserRole = 'admin' | 'editor' | 'viewer' | 'guest';
|
||
|
||
/** Estados posibles de una publicación */
|
||
export type PostStatus = 'borrador' | 'pendiente' | 'publicado' | 'archivado';
|
||
|
||
// ─────────────────────────────────────────────
|
||
// CORE ENTITIES
|
||
// ─────────────────────────────────────────────
|
||
|
||
/** Entidad del perfil de usuario autenticado */
|
||
export interface AuthUser {
|
||
$id: string;
|
||
name: string;
|
||
email: string;
|
||
labels?: string[];
|
||
prefs: {
|
||
role?: UserRole;
|
||
[key: string]: unknown;
|
||
};
|
||
}
|
||
|
||
/** Entidad de tipo de publicación */
|
||
export interface PublicationType {
|
||
$id: string;
|
||
codigo: string;
|
||
descripcion: string;
|
||
}
|
||
|
||
/** Entidad de ítem de media */
|
||
export interface MediaItem {
|
||
$id: string;
|
||
file_id: string;
|
||
bucket_id: string;
|
||
titulo: string;
|
||
alt_text?: string;
|
||
descripcion_seo?: string;
|
||
tipo: 'imagen' | 'video';
|
||
}
|
||
|
||
/** Entidad de cliente/patrocinador */
|
||
export interface Client {
|
||
$id: string;
|
||
nombre_entidad: string;
|
||
nit?: string;
|
||
slug: string;
|
||
contacto_nombre: string;
|
||
numero_whatsapp: string;
|
||
estado: boolean;
|
||
}
|
||
|
||
/** Entidad principal de publicación (Post) */
|
||
export interface Post {
|
||
$id: string;
|
||
$createdAt: string;
|
||
$updatedAt: string;
|
||
titulo: string;
|
||
slug: string;
|
||
contenido: string;
|
||
resumen_redes?: string;
|
||
estado: PostStatus;
|
||
fecha_publicacion: string;
|
||
fecha_finalizacion?: string;
|
||
og_image_url?: string;
|
||
url_destino?: string;
|
||
video_url?: string;
|
||
seo_titulo?: string;
|
||
seo_descripcion?: string;
|
||
// Relaciones (pueden llegar como string ID o como objeto resuelto)
|
||
tipo_publicacion_id: string | PublicationType;
|
||
imagen_destacada_id?: string | MediaItem;
|
||
cliente_id?: string | Client;
|
||
resolved_media?: MediaItem;
|
||
}
|
||
|
||
// ─────────────────────────────────────────────
|
||
// COMPONENT PROPS
|
||
// ─────────────────────────────────────────────
|
||
|
||
/** Props del PostCard (componente de dashboard) */
|
||
export interface PostCardProps {
|
||
post: Post;
|
||
userRole: UserRole;
|
||
onEdit?: (post: Post) => void;
|
||
onDelete?: (postId: string) => void;
|
||
/** URL base del endpoint de Appwrite para construir URLs de imagen */
|
||
appwriteEndpoint: string;
|
||
appwriteProjectId: string;
|
||
globalSettings?: Record<string, any>;
|
||
}
|
||
|
||
/** Props del PermissionGuard HOC */
|
||
export interface PermissionGuardProps {
|
||
/** Roles que tienen acceso al contenido protegido */
|
||
allowedRoles: UserRole[];
|
||
/** Rol actual del usuario */
|
||
userRole: UserRole;
|
||
/** Contenido a renderizar si el usuario tiene permiso */
|
||
children: React.ReactNode;
|
||
/** Contenido alternativo si no tiene permiso (opcional) */
|
||
fallback?: React.ReactNode;
|
||
}
|
||
|
||
/** Props del FormSection */
|
||
export interface FormSectionProps {
|
||
title: string;
|
||
icon?: React.ReactNode;
|
||
/** Número de columnas del grid interno (1–12) */
|
||
columns?: 1 | 2 | 3 | 4 | 6 | 12;
|
||
children: React.ReactNode;
|
||
/** Clase CSS adicional */
|
||
className?: string;
|
||
}
|
||
|
||
/** Props del RelationSelectField */
|
||
export interface RelationSelectFieldProps {
|
||
/** Nombre del campo en el formulario */
|
||
name: string;
|
||
/** Label visible */
|
||
label: string;
|
||
/** Opciones actuales disponibles */
|
||
options: Array<{ $id: string; [key: string]: unknown }>;
|
||
/** Propiedad del objeto a mostrar como texto */
|
||
labelKey: string;
|
||
/** Valor actualmente seleccionado */
|
||
value?: string;
|
||
onChange?: (value: string) => void;
|
||
/** Colección de Appwrite para creación rápida */
|
||
relationCollection: string;
|
||
/** Si el campo es obligatorio */
|
||
required?: boolean;
|
||
/** Desactiva el campo */
|
||
disabled?: boolean;
|
||
}
|
||
|
||
/** Props del PublicationLayout */
|
||
export interface PublicationLayoutProps {
|
||
/** Post existente para edición, undefined para creación */
|
||
initialData?: Partial<Post>;
|
||
/** Datos de relaciones pre-cargados desde el servidor */
|
||
relationData: Record<string, Array<{ $id: string; [key: string]: unknown }>>;
|
||
/** Acción de servidor para guardar */
|
||
/** Acción de servidor para guardar. Puede retornar un objeto de éxito o void (si redirige) */
|
||
submitAction: (formData: FormData) => Promise<{ success: boolean; error?: string; data?: unknown } | void>;
|
||
/** Usuario autenticado */
|
||
user: AuthUser;
|
||
/** Config de Appwrite para URLs de media */
|
||
appwriteConfig: {
|
||
endpoint: string;
|
||
projectId: string;
|
||
databaseId: string;
|
||
};
|
||
}
|
||
|
||
// ─────────────────────────────────────────────
|
||
// STORE TYPES (Zustand)
|
||
// ─────────────────────────────────────────────
|
||
|
||
/** Estado del store de publicaciones */
|
||
export interface PublicationStoreState {
|
||
/** Cache de opciones para campos de relación — evita re-fetches */
|
||
relationCache: Record<string, Array<{ $id: string; [key: string]: unknown }>>;
|
||
/** Campo actualmente abierto en QuickCreateModal */
|
||
pendingRelationField: string | null;
|
||
/** Colección destino del modal de creación rápida */
|
||
pendingRelationCollection: string | null;
|
||
/** Estado de la UI optimista durante el guardado */
|
||
optimisticState: 'idle' | 'saving' | 'saved' | 'error';
|
||
/** Mensaje de error si aplica */
|
||
errorMessage: string | null;
|
||
}
|
||
|
||
/** Acciones del store de publicaciones */
|
||
export interface PublicationStoreActions {
|
||
/** Abre el QuickCreateModal para un campo de relación específico */
|
||
openQuickCreate: (fieldName: string, collection: string) => void;
|
||
/** Cierra el QuickCreateModal */
|
||
closeQuickCreate: () => void;
|
||
/** Inyecta un nuevo documento en el cache y en el campo padre */
|
||
injectRelationValue: (
|
||
fieldName: string,
|
||
collection: string,
|
||
newDoc: { $id: string; [key: string]: unknown }
|
||
) => void;
|
||
/** Actualiza el cache de opciones de una relación */
|
||
setRelationCache: (
|
||
collection: string,
|
||
data: Array<{ $id: string; [key: string]: unknown }>
|
||
) => void;
|
||
/** Establece el estado optimista */
|
||
setOptimisticState: (state: PublicationStoreState['optimisticState'], error?: string) => void;
|
||
/** Reinicia el store */
|
||
reset: () => void;
|
||
}
|
||
|
||
export type PublicationStore = PublicationStoreState & PublicationStoreActions;
|
||
|
||
// ─────────────────────────────────────────────
|
||
// API TYPES
|
||
// ─────────────────────────────────────────────
|
||
|
||
/** Respuesta estándar de la API de publicaciones */
|
||
export interface ApiResponse<T = unknown> {
|
||
success: boolean;
|
||
data?: T;
|
||
error?: string;
|
||
validationErrors?: Record<string, string[]>;
|
||
}
|