/** * Published Page Configuration * Centralized config for Published page table, filters, and actions */ import { Content } from '../../services/api'; import Badge from '../../components/ui/badge/Badge'; import { formatRelativeDate } from '../../utils/date'; import { CheckCircleIcon, ArrowRightIcon } from '../../icons'; import { STRUCTURE_LABELS, TYPE_LABELS } from '../structureMapping'; export interface ColumnConfig { key: string; label: string; sortable?: boolean; sortField?: string; align?: 'left' | 'center' | 'right'; width?: string; numeric?: boolean; date?: boolean; render?: (value: any, row: any) => React.ReactNode; toggleable?: boolean; toggleContentKey?: string; toggleContentLabel?: string; defaultVisible?: boolean; } export interface FilterConfig { key: string; label: string; type: 'text' | 'select'; placeholder?: string; options?: Array<{ value: string; label: string }>; } export interface HeaderMetricConfig { label: string; accentColor: 'blue' | 'green' | 'amber' | 'purple'; calculate: (data: { content: Content[]; totalCount: number }) => number; } export interface PublishedPageConfig { columns: ColumnConfig[]; filters: FilterConfig[]; headerMetrics: HeaderMetricConfig[]; } export function createPublishedPageConfig(params: { searchTerm: string; setSearchTerm: (value: string) => void; statusFilter: string; setStatusFilter: (value: string) => void; publishStatusFilter: string; setPublishStatusFilter: (value: string) => void; setCurrentPage: (page: number) => void; activeSector: { id: number; name: string } | null; onRowClick?: (row: Content) => void; }): PublishedPageConfig { const showSectorColumn = !params.activeSector; const columns: ColumnConfig[] = [ { key: 'title', label: 'Title', sortable: true, sortField: 'title', render: (value: string, row: Content) => (
{params.onRowClick ? ( ) : ( {value || `Content #${row.id}`} )} {row.external_url && ( )}
), }, { key: 'status', label: 'Content Status', sortable: true, sortField: 'status', width: '120px', render: (value: string) => { const statusConfig: Record = { draft: { color: 'amber', label: 'Draft' }, published: { color: 'success', label: 'Published' }, }; const config = statusConfig[value] || { color: 'amber' as const, label: value }; return ( {config.label} ); }, }, { key: 'wordpress_status', label: 'WP Status', sortable: false, width: '120px', render: (_value: any, row: Content) => { // Check if content has been published to WordPress if (!row.external_id) { return ( Not Published ); } // WordPress status badge - use external_status if available, otherwise show 'Published' const wpStatus = (row as any).wordpress_status || 'publish'; const statusConfig: Record = { publish: { color: 'success', label: 'Published' }, draft: { color: 'gray', label: 'Draft' }, pending: { color: 'amber', label: 'Pending' }, future: { color: 'blue', label: 'Scheduled' }, private: { color: 'amber', label: 'Private' }, trash: { color: 'red', label: 'Trashed' }, }; const config = statusConfig[wpStatus] || { color: 'success' as const, label: 'Published' }; return ( {config.label} ); }, }, { key: 'content_type', label: 'Type', sortable: true, sortField: 'content_type', width: '110px', render: (value: string) => { const label = TYPE_LABELS[value] || value || '-'; const properCase = label.charAt(0).toUpperCase() + label.slice(1); return ( {properCase} ); }, }, { key: 'content_structure', label: 'Structure', sortable: true, sortField: 'content_structure', width: '130px', render: (value: string) => { const label = STRUCTURE_LABELS[value] || value || '-'; const properCase = label.split(/[_\s]+/).map(word => word.charAt(0).toUpperCase() + word.slice(1) ).join(' '); return ( {properCase} ); }, }, { key: 'cluster_name', label: 'Cluster', sortable: false, width: '130px', render: (_value: any, row: Content) => { const clusterName = row.cluster_name; if (!clusterName) { return -; } return ( {clusterName} ); }, }, { key: 'tags', label: 'Tags', sortable: false, width: '150px', render: (_value: any, row: Content) => { const tags = row.tags || []; if (!tags || tags.length === 0) { return -; } return (
{tags.slice(0, 2).map((tag, index) => ( {tag} ))} {tags.length > 2 && ( +{tags.length - 2} )}
); }, }, { key: 'categories', label: 'Categories', sortable: false, width: '150px', render: (_value: any, row: Content) => { const categories = row.categories || []; if (!categories || categories.length === 0) { return -; } return (
{categories.slice(0, 2).map((category, index) => ( {category} ))} {categories.length > 2 && ( +{categories.length - 2} )}
); }, }, { key: 'word_count', label: 'Words', sortable: true, sortField: 'word_count', numeric: true, width: '100px', align: 'right' as const, render: (value: number) => ( {value ? value.toLocaleString() : '-'} ), }, { key: 'created_at', label: 'Created', sortable: true, sortField: 'created_at', date: true, width: '140px', render: (value: string) => ( {formatRelativeDate(value)} ), }, ]; const filters: FilterConfig[] = [ { key: 'search', label: 'Search', type: 'text', placeholder: 'Search published content...', }, { key: 'status', label: 'Content Status', type: 'select', options: [ { value: '', label: 'All Statuses' }, { value: 'draft', label: 'Draft' }, { value: 'published', label: 'Published' }, ], }, { key: 'publishStatus', label: 'WordPress Status', type: 'select', options: [ { value: '', label: 'All' }, { value: 'published', label: 'Published to WP' }, { value: 'not_published', label: 'Not Published' }, ], }, ]; const headerMetrics: HeaderMetricConfig[] = [ { label: 'Total Published', accentColor: 'green', calculate: (data: { totalCount: number }) => data.totalCount, }, { label: 'On WordPress', accentColor: 'blue', calculate: (data: { content: Content[] }) => data.content.filter(c => c.external_id).length, }, ]; return { columns, filters, headerMetrics, }; }