more fixes

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-27 06:53:36 +00:00
parent 302af6337e
commit d5bda678fd
11 changed files with 34 additions and 24 deletions

View File

@@ -156,7 +156,7 @@ const LayoutContent: React.FC = () => {
<div <div
className={`flex-1 transition-all duration-300 ease-in-out ${ className={`flex-1 transition-all duration-300 ease-in-out ${
isExpanded || isHovered ? "lg:ml-[290px]" : "lg:ml-[90px]" 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 /> <AppHeader />
{/* Pending Payment Banner - Shows when account status is 'pending_payment' */} {/* Pending Payment Banner - Shows when account status is 'pending_payment' */}

View File

@@ -452,10 +452,12 @@ const AppSidebar: React.FC = () => {
onMouseEnter={() => !isExpanded && setIsHovered(true)} onMouseEnter={() => !isExpanded && setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)} onMouseLeave={() => setIsHovered(false)}
> >
{/* Collapse/Expand Toggle Button - Attached to border */} {/* Collapse/Expand Toggle Button - Position changes based on state */}
<button <button
onClick={toggleSidebar} 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"} aria-label={isExpanded ? "Collapse Sidebar" : "Expand Sidebar"}
> >
<svg <svg

View File

@@ -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="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 justify-between mb-3">
<div className="flex items-center gap-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"> <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" /> <FileTextIcon className="size-5 text-white" />
</div> </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>
<div className="text-right">&nbsp;</div> <div className="text-right">&nbsp;</div>
</div> </div>

View File

@@ -411,7 +411,6 @@ export default function Clusters() {
onClick: () => handleBulkAction('auto_generate_ideas', selectedIds), onClick: () => handleBulkAction('auto_generate_ideas', selectedIds),
variant: 'success', variant: 'success',
}} }}
getRowClassName={(row) => (row.ideas_count || 0) > 0 ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key, value) => { onFilterChange={(key, value) => {
const stringValue = value === null || value === undefined ? '' : String(value); const stringValue = value === null || value === undefined ? '' : String(value);
if (key === 'search') { if (key === 'search') {

View File

@@ -322,7 +322,6 @@ export default function Ideas() {
onClick: () => handleBulkAction('queue_to_writer', selectedIds), onClick: () => handleBulkAction('queue_to_writer', selectedIds),
variant: 'success', variant: 'success',
}} }}
getRowClassName={(row) => row.status === 'queued' || row.status === 'completed' ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key, value) => { onFilterChange={(key, value) => {
const stringValue = value === null || value === undefined ? '' : String(value); const stringValue = value === null || value === undefined ? '' : String(value);
if (key === 'search') { if (key === 'search') {

View File

@@ -603,7 +603,6 @@ export default function Keywords() {
onClick: () => handleBulkAction('auto_cluster', selectedIds), onClick: () => handleBulkAction('auto_cluster', selectedIds),
variant: 'success', variant: 'success',
}} }}
getRowClassName={(row) => row.cluster_id ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key, value) => { onFilterChange={(key, value) => {
// Normalize value to string, preserving empty strings // Normalize value to string, preserving empty strings
const stringValue = value === null || value === undefined ? '' : String(value); const stringValue = value === null || value === undefined ? '' : String(value);

View File

@@ -37,7 +37,6 @@ export default function Approved() {
// Filter state - default to approved status // Filter state - default to approved status
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState('approved'); // Default to approved
const [publishStatusFilter, setPublishStatusFilter] = useState(''); const [publishStatusFilter, setPublishStatusFilter] = useState('');
const [selectedIds, setSelectedIds] = useState<string[]>([]); const [selectedIds, setSelectedIds] = useState<string[]>([]);
@@ -51,7 +50,7 @@ export default function Approved() {
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
const [showContent, setShowContent] = useState(false); 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 () => { const loadContent = useCallback(async () => {
setLoading(true); setLoading(true);
setShowContent(false); setShowContent(false);
@@ -60,7 +59,7 @@ export default function Approved() {
const filters: ContentFilters = { const filters: ContentFilters = {
...(searchTerm && { search: searchTerm }), ...(searchTerm && { search: searchTerm }),
status: 'approved', // Always filter for approved status status: 'published', // Backend uses 'published' for approved content
page: currentPage, page: currentPage,
page_size: pageSize, page_size: pageSize,
ordering, ordering,
@@ -109,7 +108,7 @@ export default function Approved() {
setShowContent(true); setShowContent(true);
setLoading(false); setLoading(false);
} }
}, [currentPage, statusFilter, publishStatusFilter, sortBy, sortDirection, searchTerm, pageSize, toast]); }, [currentPage, publishStatusFilter, sortBy, sortDirection, searchTerm, pageSize, toast]);
useEffect(() => { useEffect(() => {
loadContent(); loadContent();
@@ -326,7 +325,6 @@ export default function Approved() {
onClick: () => handleBulkAction('bulk_publish_wordpress', selectedIds), onClick: () => handleBulkAction('bulk_publish_wordpress', selectedIds),
variant: 'success', variant: 'success',
}} }}
getRowClassName={(row) => row.external_id ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key: string, value: any) => { onFilterChange={(key: string, value: any) => {
if (key === 'search') { if (key === 'search') {
setSearchTerm(value); setSearchTerm(value);

View File

@@ -242,7 +242,6 @@ export default function Content() {
status: statusFilter, status: statusFilter,
source: sourceFilter, source: sourceFilter,
}} }}
getRowClassName={(row) => row.status === 'review' || row.status === 'published' ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key: string, value: any) => { onFilterChange={(key: string, value: any) => {
if (key === 'search') { if (key === 'search') {
setSearchTerm(value); setSearchTerm(value);

View File

@@ -416,7 +416,6 @@ export default function Review() {
onClick: () => handleBulkAction('bulk_approve', selectedIds), onClick: () => handleBulkAction('bulk_approve', selectedIds),
variant: 'success', variant: 'success',
}} }}
getRowClassName={(row) => row.status === 'approved' ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key, value) => { onFilterChange={(key, value) => {
const stringValue = value === null || value === undefined ? '' : String(value); const stringValue = value === null || value === undefined ? '' : String(value);
if (key === 'search') { if (key === 'search') {

View File

@@ -385,7 +385,6 @@ export default function Tasks() {
content_type: typeFilter, content_type: typeFilter,
source: sourceFilter, source: sourceFilter,
}} }}
getRowClassName={(row) => row.status === 'completed' ? 'bg-success-50 dark:bg-success-500/10' : ''}
onFilterChange={(key, value) => { onFilterChange={(key, value) => {
const stringValue = value === null || value === undefined ? '' : String(value); const stringValue = value === null || value === undefined ? '' : String(value);
if (key === 'search') { if (key === 'search') {

View File

@@ -22,6 +22,18 @@ import {
TableRow, TableRow,
TableCell, TableCell,
} from '../components/ui/table'; } 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 Checkbox from '../components/form/input/Checkbox';
import Button from '../components/ui/button/Button'; import Button from '../components/ui/button/Button';
import Input from '../components/form/input/InputField'; 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 { Dropdown } from '../components/ui/dropdown/Dropdown';
import { DropdownItem } from '../components/ui/dropdown/DropdownItem'; import { DropdownItem } from '../components/ui/dropdown/DropdownItem';
import AlertModal from '../components/ui/alert/AlertModal'; 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 { useHeaderMetrics } from '../context/HeaderMetricsContext';
import { useToast } from '../components/ui/toast/ToastContainer'; import { useToast } from '../components/ui/toast/ToastContainer';
import { getDeleteModalConfig } from '../config/pages/delete-modal.config'; import { getDeleteModalConfig } from '../config/pages/delete-modal.config';
@@ -571,7 +584,8 @@ export default function TablePageTemplate({
size="md" size="md"
onClick={primaryAction.onClick} onClick={primaryAction.onClick}
disabled={selectedIds.length === 0} 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} startIcon={primaryAction.icon}
className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""} className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""}
> >
@@ -597,7 +611,8 @@ export default function TablePageTemplate({
} }
}} }}
disabled={selectedIds.length === 0} 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} startIcon={bulkActions[0].icon}
className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""} className={selectedIds.length === 0 ? "opacity-50 cursor-not-allowed" : ""}
> >
@@ -667,7 +682,7 @@ export default function TablePageTemplate({
variant="secondary" variant="secondary"
size="md" size="md"
onClick={() => setShowFilters(!showFilters)} onClick={() => setShowFilters(!showFilters)}
startIcon={<ListIcon className="w-4 h-4" />} startIcon={<FunnelIcon className="w-4 h-4" />}
> >
{showFilters ? 'Hide Filters' : 'Show Filters'} {showFilters ? 'Hide Filters' : 'Show Filters'}
</Button> </Button>
@@ -800,22 +815,23 @@ export default function TablePageTemplate({
)} )}
{visibleColumnsList.map((column, colIndex) => { {visibleColumnsList.map((column, colIndex) => {
const isLastColumn = colIndex === visibleColumnsList.length - 1; const isLastColumn = colIndex === visibleColumnsList.length - 1;
const displayName = formatColumnKey(column.key);
return ( return (
<TableCell <TableCell
key={column.key} key={column.key}
isHeader 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 justify-between gap-2">
<div className="flex items-center flex-1"> <div className="flex items-center flex-1">
{column.sortable ? ( {column.sortable ? (
<div onClick={() => handleSort(column)} className="flex items-center"> <div onClick={() => handleSort(column)} className="flex items-center">
{column.label} {displayName}
{getSortIcon(column)} {getSortIcon(column)}
</div> </div>
) : ( ) : (
<> <>
{column.label} {displayName}
{getSortIcon(column)} {getSortIcon(column)}
</> </>
)} )}
@@ -825,7 +841,7 @@ export default function TablePageTemplate({
<ColumnSelector <ColumnSelector
columns={columns.map(col => ({ columns={columns.map(col => ({
key: col.key, key: col.key,
label: col.label, label: formatColumnKey(col.key),
defaultVisible: col.defaultVisible !== false, defaultVisible: col.defaultVisible !== false,
}))} }))}
visibleColumns={visibleColumns} visibleColumns={visibleColumns}