import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Clock, HelpCircle, AlignLeft, RefreshCw, Loader2 } from 'lucide-react'; import { getSectionVersions, restoreSectionVersion, SectionVersion } from '../../api/client'; import toast from 'react-hot-toast'; import { diffWords, diffLines, Change } from 'diff'; import ReactMarkdown from 'react-markdown'; interface SectionVersionsViewerProps { projectId: string; sectionId: string; currentContent: string; onClose: () => void; onRestore: (content: string) => void; } const SectionVersionsViewer: React.FC = ({ projectId, sectionId, currentContent, onClose, onRestore }) => { const [versions, setVersions] = useState([]); const [isLoading, setIsLoading] = useState(true); const [selectedVersionId, setSelectedVersionId] = useState(null); const [viewMode, setViewMode] = useState<'diff' | 'raw'>('diff'); const [diffMode, setDiffMode] = useState<'words' | 'lines'>('lines'); // Zabezpieczenie przez pomyłkowym restore const [isRestoring, setIsRestoring] = useState(false); const [showConfirm, setShowConfirm] = useState(false); useEffect(() => { const fetchVersions = async () => { setIsLoading(true); try { const data = await getSectionVersions(projectId, sectionId); setVersions(data); if (data.length > 0) { setSelectedVersionId(data[0].id); } } catch (err) { toast.error("Nie udało się pobrać historii sekcji."); } finally { setIsLoading(false); } }; fetchVersions(); }, [projectId, sectionId]); const handleRestore = async () => { if (!selectedVersionId) return; setIsRestoring(true); const toastId = toast.loading("Przywracanie wersji..."); try { await restoreSectionVersion(projectId, sectionId, selectedVersionId); const version = versions.find(v => v.id === selectedVersionId); toast.success("Przywrócono wybraną wersję. Aktualny stan zapisano do historii.", { id: toastId }); onRestore(version?.old_content || ""); onClose(); } catch (err) { toast.error("Wystąpił błąd podczas przywracania wersji.", { id: toastId }); setIsRestoring(false); setShowConfirm(false); } }; const selectedVersion = versions.find(v => v.id === selectedVersionId); // Renderer for diff const renderDiff = () => { if (!selectedVersion) return null; let diffs: Change[] = []; if (diffMode === 'words') { diffs = diffWords(selectedVersion.old_content, currentContent || ''); } else { diffs = diffLines(selectedVersion.old_content, currentContent || ''); } return (
{diffs.map((part, index) => { const color = part.added ? '#dcfce7' : part.removed ? '#fee2e2' : 'var(--text-primary)'; const bg = part.added ? 'rgba(34, 197, 94, 0.2)' : part.removed ? 'rgba(239, 68, 68, 0.2)' : 'transparent'; const textDecoration = part.removed ? 'line-through' : 'none'; return ( {part.value} ); })}
); }; return (
{/* Header */}

Wersje sekcji

Przeglądaj historyczne wersje i porównuj je z obecnym stanem

{/* Left Panel - History List */}

Dostępne wersje

{isLoading ? (
) : versions.length === 0 ? (
To jest pierwsza wersja sekcji.
Wszystkie kolejne zmiany (ręczne, z Asystenta lub Autofixu) będą tutaj widoczne.
) : (
{versions.map((ver, idx) => { const isSelected = selectedVersionId === ver.id; const dateObj = new Date(ver.timestamp); const dateStr = dateObj.toLocaleDateString('pl-PL') + ' ' + dateObj.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' }); return ( ); })}
)}
{/* Right Panel - Content and Actions */}
{selectedVersion ? ( <> {/* Toolbar Actions */}
{viewMode === 'diff' && (
Tryb:
)}
{/* Viewer Area */}
{viewMode === 'diff' ? ( <>
Tekst na czerwono był w wybranej wersji, ale nie ma go teraz. Tekst na zielono dodano w nowszych wersjach.
{renderDiff()} ) : (
{selectedVersion.old_content}
)}
{/* Bottom Action Area */}
{showConfirm ? ( Czy na pewno chcesz przywrócić tę wersję?
Aktualna zawartość sekcji zostanie automatycznie zapisana jako nowa wersja historii.
) : ( )}
) : (
Wybierz wersję z lewego panelu aby zobaczyć szczegóły.
)}
); }; export default SectionVersionsViewer;