phase 4-6 - with buggy contetn calendar page

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-16 16:55:39 +00:00
parent 1f0a31fe79
commit 7e8d667e6e
11 changed files with 3664 additions and 44 deletions

View File

@@ -0,0 +1,219 @@
import React from 'react';
import { Modal } from '../ui/modal';
import Button from '../ui/button/Button';
import { ErrorIcon, CalendarIcon, BoltIcon, ExternalLinkIcon } from '../../icons';
interface Content {
id: number;
title: string;
site_status?: string;
scheduled_publish_at?: string | null;
site_status_updated_at?: string | null;
site_status_message?: string | null;
}
interface Site {
id: number;
name: string;
platform_type: string;
}
interface ErrorDetailsModalProps {
isOpen: boolean;
onClose: () => void;
content: Content | null;
site: Site | null;
onPublishNow: () => void;
onReschedule: () => void;
onFixSettings: () => void;
}
const ErrorDetailsModal: React.FC<ErrorDetailsModalProps> = ({
isOpen,
onClose,
content,
site,
onPublishNow,
onReschedule,
onFixSettings
}) => {
if (!content || !site) return null;
const formatDate = (isoString: string | null) => {
if (!isoString) return 'N/A';
try {
const date = new Date(isoString);
return date.toLocaleString('en-US', {
month: 'long',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true
});
} catch (error) {
return isoString;
}
};
const errorMessage = content.site_status_message || 'Publishing failed with no error message.';
// Parse error message to provide helpful suggestions
const getErrorSuggestion = (error: string) => {
const lowerError = error.toLowerCase();
if (lowerError.includes('credential') || lowerError.includes('authentication') || lowerError.includes('403')) {
return 'The publishing site returned an authentication error. Please check the API key in Site Settings.';
} else if (lowerError.includes('timeout') || lowerError.includes('network')) {
return 'The publishing site did not respond in time. Please check your internet connection and site availability.';
} else if (lowerError.includes('404') || lowerError.includes('not found')) {
return 'The publishing endpoint was not found. Please verify the site URL in Site Settings.';
} else if (lowerError.includes('500') || lowerError.includes('server error')) {
return 'The publishing site returned a server error. Please try again later or contact site support.';
} else if (lowerError.includes('required field') || lowerError.includes('missing')) {
return 'Required fields are missing in the content. Please review and complete all necessary fields.';
} else if (lowerError.includes('rate limit')) {
return 'Too many requests were sent to the publishing site. Please wait a few minutes and try again.';
}
return null;
};
const suggestion = getErrorSuggestion(errorMessage);
const platformName = site.platform_type.charAt(0).toUpperCase() + site.platform_type.slice(1);
return (
<Modal
isOpen={isOpen}
onClose={onClose}
showCloseButton={true}
>
<div className="p-6">
{/* Header */}
<div className="flex items-center gap-3 mb-6">
<ErrorIcon className="w-8 h-8 text-error-500" />
<div>
<h2 className="text-xl font-semibold text-gray-900">
Publishing Error Details
</h2>
<p className="text-sm text-gray-500 mt-1">
Content failed to publish
</p>
</div>
</div>
{/* Content Details */}
<div className="space-y-3 mb-6">
<div>
<p className="text-sm font-medium text-gray-700">Content:</p>
<p className="text-sm text-gray-900 mt-1">"{content.title}"</p>
</div>
<div>
<p className="text-sm font-medium text-gray-700">Site:</p>
<p className="text-sm text-gray-900 mt-1">
{site.name} ({platformName})
</p>
</div>
{content.scheduled_publish_at && (
<div>
<p className="text-sm font-medium text-gray-700">Scheduled:</p>
<p className="text-sm text-gray-900 mt-1">
{formatDate(content.scheduled_publish_at)}
</p>
</div>
)}
{content.site_status_updated_at && (
<div>
<p className="text-sm font-medium text-gray-700">Failed:</p>
<p className="text-sm text-gray-900 mt-1">
{formatDate(content.site_status_updated_at)}
</p>
</div>
)}
</div>
{/* Error Message */}
<div className="mb-6">
<p className="text-sm font-medium text-gray-700 mb-2">Error Message:</p>
<div className="bg-error-50 border border-error-200 rounded-lg p-4">
<p className="text-sm text-error-900 whitespace-pre-wrap break-words">
{errorMessage}
</p>
</div>
</div>
{/* Suggestion */}
{suggestion && (
<div className="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6">
<div className="flex items-start gap-2">
<div className="flex-shrink-0">
<svg className="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
</svg>
</div>
<div>
<p className="text-sm font-medium text-blue-900">Suggestion:</p>
<p className="text-sm text-blue-800 mt-1">{suggestion}</p>
</div>
</div>
</div>
)}
{/* Actions */}
<div className="space-y-3">
<p className="text-sm font-medium text-gray-700">Actions:</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<Button
variant="outline"
onClick={() => {
onFixSettings();
onClose();
}}
className="w-full"
>
<ExternalLinkIcon className="w-4 h-4 mr-2" />
Fix Site Settings
</Button>
<Button
variant="outline"
onClick={() => {
onPublishNow();
onClose();
}}
className="w-full"
>
<BoltIcon className="w-4 h-4 mr-2" />
Publish Now
</Button>
<Button
variant="outline"
onClick={() => {
onReschedule();
onClose();
}}
className="w-full"
>
<CalendarIcon className="w-4 h-4 mr-2" />
Reschedule
</Button>
<Button
variant="outline"
onClick={onClose}
className="w-full"
>
Close
</Button>
</div>
</div>
</div>
</Modal>
);
};
export default ErrorDetailsModal;