import React, { useState, useRef } from 'react'; import { api } from '../../services/api'; import { X, UploadCloud, Download, Loader2, CheckCircle2, AlertCircle } from 'lucide-react'; interface OPMLModalProps { onClose: () => void; onImportComplete: () => void; } export const OPMLModal: React.FC = ({ onClose, onImportComplete, }) => { const [file, setFile] = useState(null); const [loading, setLoading] = useState(false); const [result, setResult] = useState<{ imported: number; total: number } | null>(null); const [error, setError] = useState(null); const fileInputRef = useRef(null); const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { setFile(e.target.files[0]); setError(null); setResult(null); } }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { setFile(e.dataTransfer.files[0]); setError(null); setResult(null); } }; const handleImport = async () => { if (!file) return; setLoading(true); setError(null); try { const res = await api.importOPML(file); setResult({ imported: res.imported_count, total: res.total_parsed }); onImportComplete(); } catch (err: any) { setError(err.message || 'Failed to import OPML file'); } finally { setLoading(false); } }; const handleExport = () => { const url = api.exportOPMLUrl(); window.open(url, '_blank'); }; return (
e.stopPropagation()}>

OPML Migration

{error && (
{error}
)} {result && (
Imported {result.imported} new feeds ({result.total} parsed in OPML).
)} {/* Import Dropzone */}
Import Subscriptions (OPML 2.0 XML)
e.preventDefault()} onDrop={handleDrop} onClick={() => fileInputRef.current?.click()} style={{ border: '2px dashed var(--border-strong)', borderRadius: 'var(--radius-md)', padding: '1.75rem 1rem', textAlign: 'center', cursor: 'pointer', background: 'var(--bg-subtle)', }} >
{file ? file.name : 'Click to select or drop .opml / .xml file'}
{file && (
)}
{/* Export Section */}
Export Subscriptions

Download complete backup of all feeds and categories.

); };