import React, { useEffect, useState } from 'react'; import { AuthProvider, AuthGuard, useAuth } from './AdminAuth'; import AdminLayout from './AdminLayout'; interface Feed { id: number; name: string; merchant_name: string | null; is_enabled: boolean; product_count: number; last_sync_at: string | null; last_sync_status: string | null; last_error: string | null; sync_frequency: string; provider_name: string; provider_slug: string; } interface SyncLog { id: number; status: string; started_at: string; finished_at: string | null; products_processed: number; products_created: number; products_updated: number; error_message: string | null; } function StatusBadge({ status }: { status: string | null }) { const s = status || 'unknown'; const styles: Record = { success: 'bg-[#00FF6A]/10 text-[#00FF6A]', failed: 'bg-[#FF3B3B]/10 text-[#FF3B3B]', running: 'bg-[#FFD700]/10 text-[#FFD700]', unknown: 'bg-[#666]/10 text-[#666]', }; return {s}; } function timeAgo(iso: string | null): string { if (!iso) return 'Nooit'; const mins = Math.floor((Date.now() - new Date(iso).getTime()) / 60000); if (mins < 1) return 'Zojuist'; if (mins < 60) return `${mins} min geleden`; if (mins < 1440) return `${Math.floor(mins / 60)} uur geleden`; return `${Math.floor(mins / 1440)} dagen geleden`; } function FeedManagerContent() { const { token } = useAuth(); const [feeds, setFeeds] = useState([]); const [loading, setLoading] = useState(true); const [syncing, setSyncing] = useState>(new Set()); const [logsFor, setLogsFor] = useState(null); const [logs, setLogs] = useState([]); const [logsLoading, setLogsLoading] = useState(false); const headers = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }; const loadFeeds = () => { fetch('/api/admin/feeds', { headers: { Authorization: `Bearer ${token}` } }) .then(r => r.json()) .then(d => setFeeds(d.feeds || [])) .catch(() => {}) .finally(() => setLoading(false)); }; useEffect(() => { loadFeeds(); }, [token]); const toggleFeed = async (feed: Feed) => { await fetch(`/api/admin/feeds/${feed.id}`, { method: 'PUT', headers, body: JSON.stringify({ is_enabled: !feed.is_enabled }), }); setFeeds(prev => prev.map(f => f.id === feed.id ? { ...f, is_enabled: !f.is_enabled } : f)); }; const syncFeed = async (id: number) => { setSyncing(prev => new Set(prev).add(id)); try { await fetch(`/api/admin/feeds/${id}/sync`, { method: 'POST', headers }); loadFeeds(); } catch {} setSyncing(prev => { const n = new Set(prev); n.delete(id); return n; }); }; const showLogs = async (id: number) => { if (logsFor === id) { setLogsFor(null); return; } setLogsFor(id); setLogsLoading(true); try { const res = await fetch(`/api/admin/feeds/${id}/logs?limit=10`, { headers: { Authorization: `Bearer ${token}` } }); const d = await res.json(); setLogs(d.logs || []); } catch { setLogs([]); } setLogsLoading(false); }; if (loading) return
Laden...
; return ( {feeds.length === 0 ? (
📡
Geen feeds gevonden
Feeds worden aangemaakt via de sync engine
) : (
{feeds.map(feed => ( {logsFor === feed.id && ( )} ))}
Feed Provider Status Producten Laatste sync Acties
{feed.name}
{feed.merchant_name &&
{feed.merchant_name}
}
{feed.provider_name} {feed.last_error && (
{feed.last_error}
)}
{feed.product_count.toLocaleString()} {timeAgo(feed.last_sync_at)}
{logsLoading ? (
Laden...
) : logs.length === 0 ? (
Geen sync logs
) : ( {logs.map(log => ( ))}
Tijd Status Verwerkt Nieuw Updated Error
{new Date(log.started_at).toLocaleString('nl-NL')} {log.products_processed || 0} {log.products_created || 0} {log.products_updated || 0} {log.error_message || '-'}
)}
)}
); } export default function FeedManagerPage() { return ; }