@@ -1,268 +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 { fetchAPI } from '../../services/api';
|
||||
|
||||
interface BulkWordPressPublishProps {
|
||||
contentItems: Array<{
|
||||
content_id: number;
|
||||
content_title: string;
|
||||
overall_status: 'pending' | 'partial' | 'complete' | 'failed';
|
||||
}>;
|
||||
onPublishComplete?: (results: { success: string[], failed: string[] }) => void;
|
||||
}
|
||||
|
||||
interface PublishResult {
|
||||
id: number;
|
||||
title: string;
|
||||
status: 'success' | 'failed' | 'pending';
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export const BulkWordPressPublish: React.FC<BulkWordPressPublishProps> = ({
|
||||
contentItems,
|
||||
onPublishComplete
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [publishing, setPublishing] = useState(false);
|
||||
const [results, setResults] = useState<PublishResult[]>([]);
|
||||
|
||||
// Filter items that are ready to publish
|
||||
const readyToPublish = contentItems.filter(item =>
|
||||
item.overall_status === 'complete'
|
||||
);
|
||||
|
||||
const handleBulkPublish = async () => {
|
||||
if (readyToPublish.length === 0) return;
|
||||
|
||||
setPublishing(true);
|
||||
setResults([]);
|
||||
|
||||
let successCount = 0;
|
||||
let failedCount = 0;
|
||||
const publishResults: PublishResult[] = [];
|
||||
|
||||
// Process each item individually
|
||||
for (const item of readyToPublish) {
|
||||
try {
|
||||
const response = await fetchAPI(`/api/wordpress/publish/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
content_id: item.content_id.toString()
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
successCount++;
|
||||
publishResults.push({
|
||||
id: item.content_id,
|
||||
title: item.content_title,
|
||||
status: 'success',
|
||||
message: 'Published successfully'
|
||||
});
|
||||
} else {
|
||||
failedCount++;
|
||||
publishResults.push({
|
||||
id: item.content_id,
|
||||
title: item.content_title,
|
||||
status: 'failed',
|
||||
message: response.message || 'Publishing failed'
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
failedCount++;
|
||||
publishResults.push({
|
||||
id: item.content_id,
|
||||
title: item.content_title,
|
||||
status: 'failed',
|
||||
message: error.message || 'Network error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setResults(publishResults);
|
||||
setPublishing(false);
|
||||
|
||||
// Notify parent component
|
||||
if (onPublishComplete) {
|
||||
const success = publishResults.filter(r => r.status === 'success').map(r => r.id.toString());
|
||||
const failed = publishResults.filter(r => r.status === 'failed').map(r => r.id.toString());
|
||||
onPublishComplete({ success, failed });
|
||||
}
|
||||
};
|
||||
|
||||
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 (
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<PublishIcon />}
|
||||
onClick={() => setOpen(true)}
|
||||
size="small"
|
||||
>
|
||||
Publish Ready ({readyToPublish.length})
|
||||
</Button>
|
||||
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
maxWidth="md"
|
||||
fullWidth
|
||||
disableEscapeKeyDown={publishing}
|
||||
>
|
||||
<DialogTitle>
|
||||
Bulk Publish to WordPress
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
{!publishing && results.length === 0 && (
|
||||
<>
|
||||
<Typography variant="body1" gutterBottom>
|
||||
Ready to publish <strong>{readyToPublish.length}</strong> content items to WordPress:
|
||||
</Typography>
|
||||
|
||||
<Alert severity="info" sx={{ mt: 2, mb: 2 }}>
|
||||
Only content with generated images will be published.
|
||||
</Alert>
|
||||
|
||||
<Box sx={{ maxHeight: 300, overflow: 'auto', border: 1, borderColor: 'divider', borderRadius: 1 }}>
|
||||
<List dense>
|
||||
{readyToPublish.map((item, index) => (
|
||||
<div key={item.content_id}>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary={item.content_title}
|
||||
secondary={`ID: ${item.content_id}`}
|
||||
/>
|
||||
</ListItem>
|
||||
{index < readyToPublish.length - 1 && <Divider />}
|
||||
</div>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{publishing && (
|
||||
<Box display="flex" alignItems="center" gap={2} py={4}>
|
||||
<CircularProgress />
|
||||
<Typography>
|
||||
Publishing {readyToPublish.length} items to WordPress...
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!publishing && results.length > 0 && (
|
||||
<>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
{successCount > 0 && (
|
||||
<Alert severity="success" sx={{ mb: 1 }}>
|
||||
✓ Successfully published {successCount} items
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{failedCount > 0 && (
|
||||
<Alert severity="error">
|
||||
✗ Failed to publish {failedCount} items
|
||||
</Alert>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Results:
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ maxHeight: 400, overflow: 'auto', border: 1, borderColor: 'divider', borderRadius: 1 }}>
|
||||
<List dense>
|
||||
{results.map((result, index) => (
|
||||
<div key={result.id}>
|
||||
<ListItem>
|
||||
<Box display="flex" alignItems="center" width="100%">
|
||||
{result.status === 'success' ? (
|
||||
<SuccessIcon color="success" sx={{ mr: 1 }} />
|
||||
) : (
|
||||
<ErrorIcon color="error" sx={{ mr: 1 }} />
|
||||
)}
|
||||
<ListItemText
|
||||
primary={result.title}
|
||||
secondary={result.message}
|
||||
/>
|
||||
</Box>
|
||||
</ListItem>
|
||||
{index < results.length - 1 && <Divider />}
|
||||
</div>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
{!publishing && results.length === 0 && (
|
||||
<>
|
||||
<Button onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleBulkPublish}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<PublishIcon />}
|
||||
>
|
||||
Publish All ({readyToPublish.length})
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{publishing && (
|
||||
<Button disabled>
|
||||
Publishing...
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!publishing && results.length > 0 && (
|
||||
<Button onClick={handleClose} variant="contained">
|
||||
Close
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,2 @@
|
||||
export { WordPressPublish } from './WordPressPublish';
|
||||
export { BulkWordPressPublish } from './BulkWordPressPublish';
|
||||
export type { WordPressPublishProps } from './WordPressPublish';
|
||||
Reference in New Issue
Block a user