This commit is contained in:
IGNY8 VPS (Salman)
2026-01-01 10:41:31 +00:00
parent d389576634
commit 815c7b5129

View File

@@ -0,0 +1,284 @@
import React, { useState } from 'react';
import {
Button,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Typography,
Box,
LinearProgress,
Alert,
List,
ListItem,
ListItemText,
ListItemIcon,
CircularProgress,
Chip
} from '@mui/material';
import {
Publish as PublishIcon,
CheckCircle as SuccessIcon,
Error as ErrorIcon,
Schedule as PendingIcon
} from '@mui/icons-material';
import { api } from '../../services/api';
interface BulkWordPressPublishProps {
selectedContentIds: string[];
contentItems: Array<{
id: string;
title: string;
status: string;
}>;
onPublishComplete: () => void;
onClose: () => void;
}
interface BulkPublishResult {
total: number;
queued: number;
skipped: number;
errors: string[];
}
export const BulkWordPressPublish: React.FC<BulkWordPressPublishProps> = ({
selectedContentIds,
contentItems,
onPublishComplete,
onClose
}) => {
const [open, setOpen] = useState(false);
const [publishing, setPublishing] = useState(false);
const [result, setResult] = useState<BulkPublishResult | null>(null);
const [error, setError] = useState<string | null>(null);
const selectedItems = contentItems.filter(item =>
selectedContentIds.includes(item.id)
);
const handleBulkPublish = async () => {
setPublishing(true);
setError(null);
setResult(null);
try {
const response = await api.post('/api/v1/content/bulk-publish-to-wordpress/', {
content_ids: selectedContentIds.map(id => parseInt(id))
});
if (response.data.success) {
setResult({
total: selectedContentIds.length,
queued: response.data.data.content_count,
skipped: 0,
errors: []
});
// Start polling for individual status updates
startStatusPolling();
} else {
setError(response.data.message || 'Failed to start bulk publishing');
}
} catch (error: any) {
setError(error.response?.data?.message || 'Error starting bulk publish');
} finally {
setPublishing(false);
}
};
const startStatusPolling = () => {
// Poll for 2 minutes to check status
const pollInterval = setInterval(async () => {
try {
// Check status of all items (this could be optimized with a dedicated endpoint)
const statusPromises = selectedContentIds.map(id =>
api.get(`/api/v1/content/${id}/wordpress-status/`)
);
const responses = await Promise.allSettled(statusPromises);
let completedCount = 0;
let successCount = 0;
let failedCount = 0;
responses.forEach((response) => {
if (response.status === 'fulfilled' && response.value.data.success) {
const status = response.value.data.data.wordpress_sync_status;
if (status === 'success' || status === 'failed') {
completedCount++;
if (status === 'success') successCount++;
if (status === 'failed') failedCount++;
}
}
});
// If all items are complete, stop polling
if (completedCount === selectedContentIds.length) {
clearInterval(pollInterval);
setResult(prev => prev ? {
...prev,
queued: successCount,
errors: Array(failedCount).fill('Publishing failed')
} : null);
onPublishComplete();
}
} catch (error) {
console.error('Error polling status:', error);
}
}, 5000);
// Stop polling after 2 minutes
setTimeout(() => {
clearInterval(pollInterval);
}, 120000);
};
const handleOpen = () => {
setOpen(true);
setResult(null);
setError(null);
};
const handleClose = () => {
setOpen(false);
onClose();
};
const getResultSummary = () => {
if (!result) return null;
const { total, queued, skipped, errors } = result;
const failed = errors.length;
return (
<Box sx={{ mt: 2 }}>
<Typography variant="h6" gutterBottom>
Bulk Publish Results
</Typography>
<Box display="flex" gap={1} flexWrap="wrap" mb={2}>
<Chip
icon={<SuccessIcon />}
label={`${queued} Queued`}
color="success"
size="small"
/>
{skipped > 0 && (
<Chip
icon={<PendingIcon />}
label={`${skipped} Skipped`}
color="warning"
size="small"
/>
)}
{failed > 0 && (
<Chip
icon={<ErrorIcon />}
label={`${failed} Failed`}
color="error"
size="small"
/>
)}
</Box>
{failed > 0 && (
<Alert severity="warning" sx={{ mt: 1 }}>
Some items failed to publish. Check individual item status for details.
</Alert>
)}
</Box>
);
};
return (
<>
<Button
variant="contained"
color="primary"
startIcon={<PublishIcon />}
onClick={handleOpen}
disabled={selectedContentIds.length === 0}
>
Bulk Publish to Site ({selectedContentIds.length})
</Button>
<Dialog
open={open}
onClose={handleClose}
maxWidth="md"
fullWidth
>
<DialogTitle>
Bulk Publish to Site
</DialogTitle>
<DialogContent>
{!publishing && !result && (
<>
<Typography variant="body1" gutterBottom>
You are about to publish {selectedContentIds.length} content items to your site:
</Typography>
<List dense sx={{ maxHeight: 300, overflow: 'auto', mt: 2 }}>
{selectedItems.map((item) => (
<ListItem key={item.id}>
<ListItemIcon>
<PublishIcon />
</ListItemIcon>
<ListItemText
primary={item.title}
secondary={`Status: ${item.status}`}
/>
</ListItem>
))}
</List>
<Alert severity="info" sx={{ mt: 2 }}>
This will create new posts on your WordPress site with all content,
images, categories, and SEO metadata. Items already published will be skipped.
</Alert>
</>
)}
{publishing && (
<Box sx={{ py: 3 }}>
<Box display="flex" alignItems="center" gap={2} mb={2}>
<CircularProgress size={24} />
<Typography>Queuing content for WordPress publishing...</Typography>
</Box>
<LinearProgress />
</Box>
)}
{result && getResultSummary()}
{error && (
<Alert severity="error" sx={{ mt: 2 }}>
{error}
</Alert>
)}
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>
{result ? 'Close' : 'Cancel'}
</Button>
{!publishing && !result && (
<Button
onClick={handleBulkPublish}
color="primary"
variant="contained"
disabled={selectedContentIds.length === 0}
>
Publish All to Site
</Button>
)}
</DialogActions>
</Dialog>
</>
);
};
export default BulkWordPressPublish;