diff --git a/frontend/src/components/WordPressPublish/BulkWordPressPublish.tsx b/frontend/src/components/WordPressPublish/BulkWordPressPublish.tsx deleted file mode 100644 index f6e790d9..00000000 --- a/frontend/src/components/WordPressPublish/BulkWordPressPublish.tsx +++ /dev/null @@ -1,260 +0,0 @@ -import React, { useState } from 'react'; -import { - Button, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - Typography, - Alert, - Box, - CircularProgress, - List, - ListItem, - ListItemText, - Divider -} from '@mui/material'; -import { - Publish as PublishIcon, - CheckCircle as SuccessIcon, - Error as ErrorIcon -} from '@mui/icons-material'; -import { api } from '../../services/api'; - -interface BulkWordPressPublishProps { - contentItems: Array<{ - id: string; - title: string; - imageGenerationStatus: 'pending' | 'generating' | 'complete' | 'failed'; - wordpressStatus: 'draft' | 'publishing' | 'published' | 'failed'; - }>; - onPublishComplete?: (results: { success: string[], failed: string[] }) => void; -} - -interface PublishResult { - id: string; - title: string; - status: 'success' | 'failed' | 'pending'; - message?: string; -} - -export const BulkWordPressPublish: React.FC = ({ - contentItems, - onPublishComplete -}) => { - const [open, setOpen] = useState(false); - const [publishing, setPublishing] = useState(false); - const [results, setResults] = useState([]); - - // Filter items that are ready to publish - const readyToPublish = contentItems.filter(item => - item.imageGenerationStatus === 'complete' && - item.wordpressStatus !== 'published' && - item.wordpressStatus !== 'publishing' - ); - - const handleBulkPublish = async () => { - if (readyToPublish.length === 0) return; - - setPublishing(true); - setResults([]); - - try { - const response = await api.post('/api/wordpress/bulk-publish/', { - content_ids: readyToPublish.map(item => item.id) - }); - - if (response.data.success) { - const publishResults: PublishResult[] = response.data.data.results.map((result: any) => ({ - id: result.content_id, - title: readyToPublish.find(item => item.id === result.content_id)?.title || 'Unknown', - status: result.success ? 'success' : 'failed', - message: result.message - })); - - setResults(publishResults); - - // Notify parent component - if (onPublishComplete) { - const success = publishResults.filter(r => r.status === 'success').map(r => r.id); - const failed = publishResults.filter(r => r.status === 'failed').map(r => r.id); - onPublishComplete({ success, failed }); - } - } else { - // Handle API error - const failedResults: PublishResult[] = readyToPublish.map(item => ({ - id: item.id, - title: item.title, - status: 'failed', - message: response.data.message || 'Failed to publish' - })); - setResults(failedResults); - } - } catch (error) { - console.error('Bulk publish error:', error); - const failedResults: PublishResult[] = readyToPublish.map(item => ({ - id: item.id, - title: item.title, - status: 'failed', - message: 'Network error or server unavailable' - })); - setResults(failedResults); - } finally { - setPublishing(false); - } - }; - - const handleClose = () => { - if (!publishing) { - setOpen(false); - setResults([]); - } - }; - - const successCount = results.filter(r => r.status === 'success').length; - const failedCount = results.filter(r => r.status === 'failed').length; - - if (readyToPublish.length === 0) { - return null; // Don't show button if nothing to publish - } - - return ( - <> - - - - - Bulk Publish to WordPress - - - - {!publishing && results.length === 0 && ( - <> - - Ready to publish {readyToPublish.length} content items to WordPress: - - - - Only content with generated images and not yet published will be included. - - - - - {readyToPublish.map((item, index) => ( -
- - - - {index < readyToPublish.length - 1 && } -
- ))} -
-
- - )} - - {publishing && ( - - - - Publishing {readyToPublish.length} items to WordPress... - - - )} - - {!publishing && results.length > 0 && ( - <> - - {successCount > 0 && ( - - ✓ Successfully published {successCount} items - - )} - - {failedCount > 0 && ( - - ✗ Failed to publish {failedCount} items - - )} - - - - Results: - - - - - {results.map((result, index) => ( -
- - - {result.status === 'success' ? ( - - ) : ( - - )} - - - - {index < results.length - 1 && } -
- ))} -
-
- - )} -
- - - {!publishing && results.length === 0 && ( - <> - - - - )} - - {publishing && ( - - )} - - {!publishing && results.length > 0 && ( - - )} - -
- - ); -}; \ No newline at end of file diff --git a/frontend/src/components/WordPressPublish/ContentActionsMenu.tsx b/frontend/src/components/WordPressPublish/ContentActionsMenu.tsx deleted file mode 100644 index 3a87de06..00000000 --- a/frontend/src/components/WordPressPublish/ContentActionsMenu.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import React, { useState } from 'react'; -import { - IconButton, - Menu, - MenuItem, - ListItemIcon, - ListItemText, - Divider -} from '@mui/material'; -import { - MoreVert as MoreVertIcon, - Publish as PublishIcon, - Edit as EditIcon, - Image as ImageIcon, - GetApp as ExportIcon, - Delete as DeleteIcon -} from '@mui/icons-material'; -import { WordPressPublish } from './WordPressPublish'; - -interface ContentActionsMenuProps { - contentId: string; - contentTitle: string; - imageGenerationStatus: 'pending' | 'generating' | 'complete' | 'failed'; - wordpressStatus: 'draft' | 'publishing' | 'published' | 'failed'; - onEdit?: () => void; - onGenerateImage?: () => void; - onExport?: () => void; - onDelete?: () => void; - onWordPressStatusChange?: (status: string) => void; -} - -export const ContentActionsMenu: React.FC = ({ - contentId, - contentTitle, - imageGenerationStatus, - wordpressStatus, - onEdit, - onGenerateImage, - onExport, - onDelete, - onWordPressStatusChange -}) => { - const [anchorEl, setAnchorEl] = useState(null); - const [showWordPressDialog, setShowWordPressDialog] = useState(false); - const open = Boolean(anchorEl); - - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const handlePublishClick = () => { - setShowWordPressDialog(true); - handleClose(); - }; - - const handleMenuAction = (action: () => void) => { - action(); - handleClose(); - }; - - // Check if WordPress publishing is available - const canPublishToWordPress = imageGenerationStatus === 'complete' && - wordpressStatus !== 'published' && - wordpressStatus !== 'publishing'; - - return ( - <> - - - - - - {/* WordPress Publishing - Only show if images are ready */} - {canPublishToWordPress && ( - <> - - - - - Publish to WordPress - - - - )} - - {/* Edit Action */} - {onEdit && ( - handleMenuAction(onEdit)}> - - - - Edit - - )} - - {/* Generate Image Action */} - {onGenerateImage && ( - handleMenuAction(onGenerateImage)}> - - - - Generate Image Prompts - - )} - - {/* Export Action */} - {onExport && ( - handleMenuAction(onExport)}> - - - - Export - - )} - - {/* Delete Action */} - {onDelete && ( - <> - - handleMenuAction(onDelete)} sx={{ color: 'error.main' }}> - - - - Delete - - - )} - - - {/* WordPress Publish Dialog */} - {showWordPressDialog && ( - - )} - - ); -}; \ No newline at end of file diff --git a/frontend/src/components/WordPressPublish/WordPressPublish.tsx b/frontend/src/components/WordPressPublish/WordPressPublish.tsx index d020db0f..e5a97f4a 100644 --- a/frontend/src/components/WordPressPublish/WordPressPublish.tsx +++ b/frontend/src/components/WordPressPublish/WordPressPublish.tsx @@ -27,10 +27,8 @@ export interface WordPressPublishProps { contentId: string; contentTitle: string; currentStatus?: 'draft' | 'publishing' | 'published' | 'failed'; - imageGenerationStatus?: 'pending' | 'generating' | 'complete' | 'failed'; onStatusChange?: (status: string) => void; size?: 'small' | 'medium' | 'large'; - showOnlyIfImagesReady?: boolean; } interface WordPressStatus { @@ -45,10 +43,8 @@ export const WordPressPublish: React.FC = ({ contentId, contentTitle, currentStatus = 'draft', - imageGenerationStatus = 'pending', onStatusChange, - size = 'medium', - showOnlyIfImagesReady = false + size = 'medium' }) => { const [wpStatus, setWpStatus] = useState(null); const [loading, setLoading] = useState(false); @@ -197,34 +193,7 @@ export const WordPressPublish: React.FC = ({ const statusInfo = getStatusInfo(); - // Don't show publish button if images aren't ready and showOnlyIfImagesReady is true - const shouldShowPublishButton = !showOnlyIfImagesReady || imageGenerationStatus === 'complete'; - - if (!shouldShowPublishButton) { - return ( - - - - {size !== 'small' && ( - } - label="Images Pending" - color="warning" - size="small" - variant="outlined" - /> - )} - - - ); - } + const renderButton = () => { if (size === 'small') { @@ -333,18 +302,7 @@ export const WordPressPublish: React.FC = ({ This will create a new post on your connected WordPress site with all content, images, categories, and SEO metadata. - - {imageGenerationStatus === 'complete' && ( - - ✓ Images are generated and ready for publishing - - )} - - {imageGenerationStatus !== 'complete' && showOnlyIfImagesReady && ( - - Images are still being generated. Please wait before publishing. - - )} + {wpStatus?.wordpress_sync_status === 'success' && ( diff --git a/frontend/src/components/WordPressPublish/index.ts b/frontend/src/components/WordPressPublish/index.ts index 5fa86535..a28104ec 100644 --- a/frontend/src/components/WordPressPublish/index.ts +++ b/frontend/src/components/WordPressPublish/index.ts @@ -1,4 +1,2 @@ export { WordPressPublish } from './WordPressPublish'; -export { BulkWordPressPublish } from './BulkWordPressPublish'; -export { ContentActionsMenu } from './ContentActionsMenu'; export type { WordPressPublishProps } from './WordPressPublish'; \ No newline at end of file diff --git a/frontend/src/config/pages/table-actions.config.tsx b/frontend/src/config/pages/table-actions.config.tsx index f7018c45..99b6a39e 100644 --- a/frontend/src/config/pages/table-actions.config.tsx +++ b/frontend/src/config/pages/table-actions.config.tsx @@ -327,10 +327,8 @@ const tableActionsConfigs: Record = { icon: , variant: 'success', shouldShow: (row: any) => { - // Only show if images are generated and not already published/publishing - return row.status === 'complete' && - (!row.wordpress_status || - (row.wordpress_status !== 'published' && row.wordpress_status !== 'publishing')); + // Only show if images are generated (complete) - WordPress status is tracked separately + return row.overall_status === 'complete'; }, }, { diff --git a/frontend/src/pages/Writer/Images.tsx b/frontend/src/pages/Writer/Images.tsx index 3b58cd51..0f544871 100644 --- a/frontend/src/pages/Writer/Images.tsx +++ b/frontend/src/pages/Writer/Images.tsx @@ -13,7 +13,8 @@ import { generateImages, bulkUpdateImagesStatus, ContentImage, - api, + fetchAPI, + publishContent, } from '../../services/api'; import { useToast } from '../../components/ui/toast/ToastContainer'; import { FileIcon, DownloadIcon, BoltIcon, TaskIcon, ImageIcon, CheckCircleIcon } from '../../icons'; @@ -208,12 +209,10 @@ export default function Images() { // Bulk action handler const handleBulkAction = useCallback(async (action: string, ids: string[]) => { if (action === 'bulk_publish_wordpress') { - // Filter to only publish items that have images generated and are not already published + // Filter to only publish items that have images generated const readyItems = images .filter(item => ids.includes(item.content_id.toString())) - .filter(item => item.status === 'complete' && - (!item.wordpress_status || - (item.wordpress_status !== 'published' && item.wordpress_status !== 'publishing'))); + .filter(item => item.overall_status === 'complete'); if (readyItems.length === 0) { toast.warning('No items are ready for WordPress publishing. Items must have generated images and not already be published.'); @@ -221,27 +220,30 @@ export default function Images() { } try { - const response = await api.post('/api/wordpress/bulk-publish/', { - content_ids: readyItems.map(item => item.content_id.toString()) - }); + let successCount = 0; + let failedCount = 0; + const errors: string[] = []; - if (response.data.success) { - const results = response.data.data.results; - const successCount = results.filter((r: any) => r.success).length; - const failedCount = results.filter((r: any) => !r.success).length; - - if (successCount > 0) { - toast.success(`Successfully published ${successCount} item(s) to WordPress`); + // Process each item individually using the existing publishContent function + for (const item of readyItems) { + try { + await publishContent(item.content_id); + successCount++; + } catch (error: any) { + failedCount++; + errors.push(`${item.content_title}: ${error.message}`); } - if (failedCount > 0) { - toast.warning(`${failedCount} item(s) failed to publish`); - } - - // Reload images to reflect the updated WordPress status - loadImages(); - } else { - toast.error(`Bulk publish failed: ${response.data.message}`); } + + if (successCount > 0) { + toast.success(`Successfully published ${successCount} item(s) to WordPress`); + } + if (failedCount > 0) { + toast.warning(`${failedCount} item(s) failed to publish`); + } + + // Reload images to reflect the updated WordPress status + loadImages(); } catch (error: any) { console.error('Bulk WordPress publish error:', error); toast.error(`Failed to bulk publish to WordPress: ${error.message || 'Network error'}`); @@ -258,19 +260,13 @@ export default function Images() { setStatusUpdateRecordName(row.content_title || `Content #${row.content_id}`); setIsStatusModalOpen(true); } else if (action === 'publish_wordpress') { - // Handle WordPress publishing for individual item + // Handle WordPress publishing for individual item using existing publishContent function try { - const response = await api.post('/api/wordpress/publish/', { - content_id: row.content_id.toString() - }); - - if (response.data.success) { - toast.success(`Successfully published "${row.content_title}" to WordPress`); - // Reload images to reflect the updated WordPress status - loadImages(); - } else { - toast.error(`Failed to publish: ${response.data.message}`); - } + // Use the existing publishContent function from the API + const result = await publishContent(row.content_id); + toast.success(`Successfully published "${row.content_title}" to WordPress! View at: ${result.external_url}`); + // Reload images to reflect the updated WordPress status + loadImages(); } catch (error: any) { console.error('WordPress publish error:', error); toast.error(`Failed to publish to WordPress: ${error.message || 'Network error'}`);