208 lines
7.3 KiB
TypeScript
208 lines
7.3 KiB
TypeScript
/**
|
|
* WordPress Integration Card Component
|
|
* Stage 4: Enhanced with sync health status and troubleshooting
|
|
* Displays WordPress integration status and quick actions
|
|
*/
|
|
import React from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { Globe, CheckCircle, XCircle, Settings, RefreshCw, AlertCircle, ExternalLink } from 'lucide-react';
|
|
import { Card } from '../ui/card';
|
|
import Button from '../ui/button/Button';
|
|
import Badge from '../ui/badge/Badge';
|
|
|
|
interface WordPressIntegration {
|
|
id: number;
|
|
site: number;
|
|
platform: string;
|
|
is_active: boolean;
|
|
sync_enabled: boolean;
|
|
sync_status: 'success' | 'failed' | 'pending' | 'healthy' | 'warning' | 'error';
|
|
last_sync_at?: string;
|
|
sync_error?: string | null;
|
|
mismatch_count?: number;
|
|
config_json?: {
|
|
site_url?: string;
|
|
};
|
|
}
|
|
|
|
interface WordPressIntegrationCardProps {
|
|
integration: WordPressIntegration | null;
|
|
onConnect: () => void;
|
|
onManage: () => void;
|
|
onSync?: () => void;
|
|
loading?: boolean;
|
|
siteId?: string | number;
|
|
}
|
|
|
|
export default function WordPressIntegrationCard({
|
|
integration,
|
|
onConnect,
|
|
onManage,
|
|
onSync,
|
|
loading = false,
|
|
siteId,
|
|
}: WordPressIntegrationCardProps) {
|
|
const navigate = useNavigate();
|
|
if (!integration) {
|
|
return (
|
|
<Card className="p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
|
<Globe className="w-6 h-6 text-indigo-600 dark:text-indigo-400" />
|
|
</div>
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
WordPress Integration
|
|
</h3>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
Connect your WordPress site to sync content
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<Button onClick={onConnect} variant="primary" disabled={loading}>
|
|
Connect WordPress
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Card className="p-6">
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-lg">
|
|
<Globe className="w-6 h-6 text-indigo-600 dark:text-indigo-400" />
|
|
</div>
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
|
WordPress Integration
|
|
</h3>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
{integration.config_json?.site_url || 'WordPress Site'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Badge
|
|
variant="soft"
|
|
color={integration.is_active ? 'success' : 'neutral'}
|
|
size="sm"
|
|
>
|
|
{integration.is_active ? 'Active' : 'Inactive'}
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
|
<div>
|
|
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Sync Status</p>
|
|
<div className="flex items-center gap-2">
|
|
{integration.sync_status === 'success' || integration.sync_status === 'healthy' ? (
|
|
<CheckCircle className="w-4 h-4 text-green-500" />
|
|
) : integration.sync_status === 'failed' || integration.sync_status === 'error' ? (
|
|
<XCircle className="w-4 h-4 text-red-500" />
|
|
) : integration.sync_status === 'warning' ? (
|
|
<AlertCircle className="w-4 h-4 text-yellow-500" />
|
|
) : (
|
|
<RefreshCw className="w-4 h-4 text-yellow-500 animate-spin" />
|
|
)}
|
|
<span className="text-sm font-medium text-gray-900 dark:text-white capitalize">
|
|
{integration.sync_status === 'healthy' ? 'Healthy' :
|
|
integration.sync_status === 'warning' ? 'Warning' :
|
|
integration.sync_status === 'error' ? 'Error' :
|
|
integration.sync_status}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<p className="text-xs text-gray-500 dark:text-gray-400 mb-1">Last Sync</p>
|
|
<p className="text-sm text-gray-900 dark:text-white">
|
|
{integration.last_sync_at
|
|
? new Date(integration.last_sync_at).toLocaleDateString()
|
|
: 'Never'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Sync Health Indicators */}
|
|
{(integration.mismatch_count !== undefined && integration.mismatch_count > 0) && (
|
|
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<AlertCircle className="w-4 h-4 text-yellow-500" />
|
|
<span className="text-sm text-gray-600 dark:text-gray-400">
|
|
{integration.mismatch_count} sync mismatch{integration.mismatch_count !== 1 ? 'es' : ''} detected
|
|
</span>
|
|
</div>
|
|
{siteId && (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => navigate(`/sites/${siteId}/sync`)}
|
|
>
|
|
View Details
|
|
<ExternalLink className="w-3 h-3 ml-1" />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{integration.sync_error && (
|
|
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
|
<div className="p-2 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
|
<div className="flex items-start gap-2">
|
|
<XCircle className="w-4 h-4 text-red-500 mt-0.5 flex-shrink-0" />
|
|
<div className="flex-1">
|
|
<p className="text-xs font-medium text-red-800 dark:text-red-300 mb-1">
|
|
Sync Error
|
|
</p>
|
|
<p className="text-xs text-red-700 dark:text-red-400">
|
|
{integration.sync_error}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center gap-2 pt-2">
|
|
<Button
|
|
onClick={onManage}
|
|
variant="outline"
|
|
size="sm"
|
|
className="flex-1"
|
|
>
|
|
<Settings className="w-4 h-4 mr-2" />
|
|
Manage
|
|
</Button>
|
|
{siteId && (
|
|
<Button
|
|
onClick={() => navigate(`/sites/${siteId}/sync`)}
|
|
variant="outline"
|
|
size="sm"
|
|
title="View Sync Dashboard"
|
|
>
|
|
<ExternalLink className="w-4 h-4" />
|
|
</Button>
|
|
)}
|
|
{onSync && (
|
|
<Button
|
|
onClick={onSync}
|
|
variant="outline"
|
|
size="sm"
|
|
disabled={loading}
|
|
>
|
|
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|