213 lines
6.9 KiB
TypeScript
213 lines
6.9 KiB
TypeScript
import React from 'react';
|
|
import { Modal } from '../ui/modal';
|
|
import Button from '../ui/button/Button';
|
|
import { ErrorIcon, CalendarIcon, BoltIcon, ExternalLinkIcon } from '../../icons';
|
|
import { formatDateTime } from '../../utils/date';
|
|
|
|
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 {
|
|
return formatDateTime(isoString);
|
|
} 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;
|