more fixes
This commit is contained in:
@@ -156,7 +156,7 @@ const LayoutContent: React.FC = () => {
|
||||
<div
|
||||
className={`flex-1 transition-all duration-300 ease-in-out ${
|
||||
isExpanded || isHovered ? "lg:ml-[290px]" : "lg:ml-[90px]"
|
||||
} ${isMobileOpen ? "ml-0" : ""} w-full max-w-full min-[1440px]:max-w-[90%]`}
|
||||
} ${isMobileOpen ? "ml-0" : ""} w-full`}
|
||||
>
|
||||
<AppHeader />
|
||||
{/* Pending Payment Banner - Shows when account status is 'pending_payment' */}
|
||||
|
||||
@@ -452,10 +452,12 @@ const AppSidebar: React.FC = () => {
|
||||
onMouseEnter={() => !isExpanded && setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
{/* Collapse/Expand Toggle Button - Attached to border */}
|
||||
{/* Collapse/Expand Toggle Button - Position changes based on state */}
|
||||
<button
|
||||
onClick={toggleSidebar}
|
||||
className="hidden lg:flex absolute -right-3 top-20 w-6 h-6 items-center justify-center bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-full shadow-sm hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors z-50"
|
||||
className={`hidden lg:flex absolute top-20 w-6 h-6 items-center justify-center bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-full shadow-sm hover:bg-gray-50 dark:hover:bg-gray-800 transition-all duration-300 z-50 ${
|
||||
isExpanded || isHovered ? '-right-3' : 'right-3'
|
||||
}`}
|
||||
aria-label={isExpanded ? "Collapse Sidebar" : "Expand Sidebar"}
|
||||
>
|
||||
<svg
|
||||
|
||||
@@ -962,14 +962,14 @@ const AutomationPage: React.FC = () => {
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* Published summary card (placed after Stage 7 in the same row) */}
|
||||
{/* Approved summary card (placed after Stage 7 in the same row) */}
|
||||
<div className="rounded-xl p-5 border-2 border-green-200 bg-gradient-to-br from-green-50 to-green-100 dark:from-green-900/10 dark:to-green-800/10 flex flex-col h-full">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="size-10 rounded-lg bg-gradient-to-br from-green-500 to-green-600 flex items-center justify-center">
|
||||
<FileTextIcon className="size-5 text-white" />
|
||||
</div>
|
||||
<div className="text-sm font-bold text-green-900 dark:text-green-100">Published</div>
|
||||
<div className="text-sm font-bold text-green-900 dark:text-green-100">Approved</div>
|
||||
</div>
|
||||
<div className="text-right"> </div>
|
||||
</div>
|
||||
|
||||
@@ -411,7 +411,6 @@ export default function Clusters() {
|
||||
onClick: () => handleBulkAction('auto_generate_ideas', selectedIds),
|
||||
variant: 'success',
|
||||
}}
|
||||
getRowClassName={(row) => (row.ideas_count || 0) > 0 ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key, value) => {
|
||||
const stringValue = value === null || value === undefined ? '' : String(value);
|
||||
if (key === 'search') {
|
||||
|
||||
@@ -322,7 +322,6 @@ export default function Ideas() {
|
||||
onClick: () => handleBulkAction('queue_to_writer', selectedIds),
|
||||
variant: 'success',
|
||||
}}
|
||||
getRowClassName={(row) => row.status === 'queued' || row.status === 'completed' ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key, value) => {
|
||||
const stringValue = value === null || value === undefined ? '' : String(value);
|
||||
if (key === 'search') {
|
||||
|
||||
@@ -603,7 +603,6 @@ export default function Keywords() {
|
||||
onClick: () => handleBulkAction('auto_cluster', selectedIds),
|
||||
variant: 'success',
|
||||
}}
|
||||
getRowClassName={(row) => row.cluster_id ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key, value) => {
|
||||
// Normalize value to string, preserving empty strings
|
||||
const stringValue = value === null || value === undefined ? '' : String(value);
|
||||
|
||||
@@ -37,7 +37,6 @@ export default function Approved() {
|
||||
|
||||
// Filter state - default to approved status
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [statusFilter, setStatusFilter] = useState('approved'); // Default to approved
|
||||
const [publishStatusFilter, setPublishStatusFilter] = useState('');
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
||||
|
||||
@@ -51,7 +50,7 @@ export default function Approved() {
|
||||
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
|
||||
const [showContent, setShowContent] = useState(false);
|
||||
|
||||
// Load content - filtered for approved status
|
||||
// Load content - filtered for approved status (API still uses 'published' internally)
|
||||
const loadContent = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setShowContent(false);
|
||||
@@ -60,7 +59,7 @@ export default function Approved() {
|
||||
|
||||
const filters: ContentFilters = {
|
||||
...(searchTerm && { search: searchTerm }),
|
||||
status: 'approved', // Always filter for approved status
|
||||
status: 'published', // Backend uses 'published' for approved content
|
||||
page: currentPage,
|
||||
page_size: pageSize,
|
||||
ordering,
|
||||
@@ -109,7 +108,7 @@ export default function Approved() {
|
||||
setShowContent(true);
|
||||
setLoading(false);
|
||||
}
|
||||
}, [currentPage, statusFilter, publishStatusFilter, sortBy, sortDirection, searchTerm, pageSize, toast]);
|
||||
}, [currentPage, publishStatusFilter, sortBy, sortDirection, searchTerm, pageSize, toast]);
|
||||
|
||||
useEffect(() => {
|
||||
loadContent();
|
||||
@@ -326,7 +325,6 @@ export default function Approved() {
|
||||
onClick: () => handleBulkAction('bulk_publish_wordpress', selectedIds),
|
||||
variant: 'success',
|
||||
}}
|
||||
getRowClassName={(row) => row.external_id ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key: string, value: any) => {
|
||||
if (key === 'search') {
|
||||
setSearchTerm(value);
|
||||
|
||||
@@ -242,7 +242,6 @@ export default function Content() {
|
||||
status: statusFilter,
|
||||
source: sourceFilter,
|
||||
}}
|
||||
getRowClassName={(row) => row.status === 'review' || row.status === 'published' ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key: string, value: any) => {
|
||||
if (key === 'search') {
|
||||
setSearchTerm(value);
|
||||
|
||||
@@ -416,7 +416,6 @@ export default function Review() {
|
||||
onClick: () => handleBulkAction('bulk_approve', selectedIds),
|
||||
variant: 'success',
|
||||
}}
|
||||
getRowClassName={(row) => row.status === 'approved' ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key, value) => {
|
||||
const stringValue = value === null || value === undefined ? '' : String(value);
|
||||
if (key === 'search') {
|
||||
|
||||
@@ -385,7 +385,6 @@ export default function Tasks() {
|
||||
content_type: typeFilter,
|
||||
source: sourceFilter,
|
||||
}}
|
||||
getRowClassName={(row) => row.status === 'completed' ? 'bg-success-50 dark:bg-success-500/10' : ''}
|
||||
onFilterChange={(key, value) => {
|
||||
const stringValue = value === null || value === undefined ? '' : String(value);
|
||||
if (key === 'search') {
|
||||
|
||||
@@ -22,6 +22,18 @@ import {
|
||||
TableRow,
|
||||
TableCell,
|
||||
} from '../components/ui/table';
|
||||
|
||||
// Helper function to format column key to display name
|
||||
// Converts snake_case/camelCase to Title Case (e.g., "content_type" -> "Content Type")
|
||||
const formatColumnKey = (key: string): string => {
|
||||
return key
|
||||
.replace(/_/g, ' ') // Replace underscores with spaces
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2') // Add space before capital letters in camelCase
|
||||
.split(' ')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
import Checkbox from '../components/form/input/Checkbox';
|
||||
import Button from '../components/ui/button/Button';
|
||||
import Input from '../components/form/input/InputField';
|
||||
@@ -29,7 +41,8 @@ import SelectDropdown from '../components/form/SelectDropdown';
|
||||
import { Dropdown } from '../components/ui/dropdown/Dropdown';
|
||||
import { DropdownItem } from '../components/ui/dropdown/DropdownItem';
|
||||
import AlertModal from '../components/ui/alert/AlertModal';
|
||||
import { ChevronDownIcon, MoreDotIcon, PlusIcon, ListIcon } from '../icons';
|
||||
import { ChevronDownIcon, MoreDotIcon, PlusIcon } from '../icons';
|
||||
import { FunnelIcon } from '@heroicons/react/24/outline';
|
||||
import { useHeaderMetrics } from '../context/HeaderMetricsContext';
|
||||
import { useToast } from '../components/ui/toast/ToastContainer';
|
||||
import { getDeleteModalConfig } from '../config/pages/delete-modal.config';
|
||||
@@ -571,7 +584,8 @@ export default function TablePageTemplate({
|
||||
size="md"
|
||||
onClick={primaryAction.onClick}
|
||||
disabled={selectedIds.length === 0}
|
||||
variant={primaryAction.variant === 'success' ? 'success' : primaryAction.variant === 'warning' ? 'primary' : 'primary'}
|
||||
variant="primary"
|
||||
tone={primaryAction.variant === 'success' ? 'success' : primaryAction.variant === 'warning' ? 'warning' : 'brand'}
|
||||
startIcon={primaryAction.icon}
|
||||
className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""}
|
||||
>
|
||||
@@ -597,7 +611,8 @@ export default function TablePageTemplate({
|
||||
}
|
||||
}}
|
||||
disabled={selectedIds.length === 0}
|
||||
variant={bulkActions[0].variant === 'success' ? 'success' : bulkActions[0].variant === 'danger' ? 'primary' : 'primary'}
|
||||
variant="primary"
|
||||
tone={bulkActions[0].variant === 'success' ? 'success' : bulkActions[0].variant === 'danger' ? 'danger' : 'brand'}
|
||||
startIcon={bulkActions[0].icon}
|
||||
className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""}
|
||||
>
|
||||
@@ -667,7 +682,7 @@ export default function TablePageTemplate({
|
||||
variant="secondary"
|
||||
size="md"
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
startIcon={<ListIcon className="w-4 h-4" />}
|
||||
startIcon={<FunnelIcon className="w-4 h-4" />}
|
||||
>
|
||||
{showFilters ? 'Hide Filters' : 'Show Filters'}
|
||||
</Button>
|
||||
@@ -800,22 +815,23 @@ export default function TablePageTemplate({
|
||||
)}
|
||||
{visibleColumnsList.map((column, colIndex) => {
|
||||
const isLastColumn = colIndex === visibleColumnsList.length - 1;
|
||||
const displayName = formatColumnKey(column.key);
|
||||
return (
|
||||
<TableCell
|
||||
key={column.key}
|
||||
isHeader
|
||||
className={`px-5 py-3 font-medium text-gray-500 text-${column.align || 'start'} text-theme-xs dark:text-gray-400 ${column.sortable ? 'cursor-pointer hover:text-gray-700 dark:hover:text-gray-300' : ''} ${isLastColumn && rowActions.length > 0 ? 'pr-16' : ''}`}
|
||||
className={`px-5 py-3 font-medium text-gray-500 text-${column.align || 'start'} text-[11px] dark:text-gray-400 ${column.sortable ? 'cursor-pointer hover:text-gray-700 dark:hover:text-gray-300' : ''} ${isLastColumn && rowActions.length > 0 ? 'pr-16' : ''}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center flex-1">
|
||||
{column.sortable ? (
|
||||
<div onClick={() => handleSort(column)} className="flex items-center">
|
||||
{column.label}
|
||||
{displayName}
|
||||
{getSortIcon(column)}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{column.label}
|
||||
{displayName}
|
||||
{getSortIcon(column)}
|
||||
</>
|
||||
)}
|
||||
@@ -825,7 +841,7 @@ export default function TablePageTemplate({
|
||||
<ColumnSelector
|
||||
columns={columns.map(col => ({
|
||||
key: col.key,
|
||||
label: col.label,
|
||||
label: formatColumnKey(col.key),
|
||||
defaultVisible: col.defaultVisible !== false,
|
||||
}))}
|
||||
visibleColumns={visibleColumns}
|
||||
|
||||
Reference in New Issue
Block a user