102 lines
2.9 KiB
TypeScript
102 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { X } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { DiffViewer } from './diff-viewer';
|
|
|
|
interface HistoryEntry {
|
|
id: string;
|
|
oldContent: string;
|
|
newContent: string;
|
|
reason: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface HistoryModalProps {
|
|
slug: string;
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function HistoryModal({ slug, isOpen, onClose }: HistoryModalProps) {
|
|
const [history, setHistory] = useState<HistoryEntry[]>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [selectedEntry, setSelectedEntry] = useState<HistoryEntry | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) return;
|
|
|
|
const fetchHistory = async () => {
|
|
setIsLoading(true);
|
|
try {
|
|
const response = await fetch(`/api/article/${encodeURIComponent(slug)}/history`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setHistory(data);
|
|
if (data.length > 0) {
|
|
setSelectedEntry(data[0]);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch history:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchHistory();
|
|
}, [slug, isOpen]);
|
|
|
|
if (!isOpen) return null;
|
|
|
|
const formatDate = (dateString: string) => {
|
|
return new Date(dateString).toLocaleString();
|
|
};
|
|
|
|
return (
|
|
<div className="history-modal-overlay" onClick={onClose}>
|
|
<div className="history-modal" onClick={(e) => e.stopPropagation()}>
|
|
<div className="history-modal-header">
|
|
<h2>Revision History</h2>
|
|
<Button variant="ghost" size="sm" onClick={onClose}>
|
|
<X className="w-5 h-5" />
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="history-modal-body">
|
|
{isLoading ? (
|
|
<div className="history-loading">Loading history...</div>
|
|
) : history.length === 0 ? (
|
|
<div className="history-empty">No revision history available.</div>
|
|
) : (
|
|
<>
|
|
<div className="history-list">
|
|
{history.map((entry) => (
|
|
<button
|
|
key={entry.id}
|
|
className={`history-item ${selectedEntry?.id === entry.id ? 'selected' : ''}`}
|
|
onClick={() => setSelectedEntry(entry)}
|
|
>
|
|
<div className="history-item-date">{formatDate(entry.createdAt)}</div>
|
|
<div className="history-item-reason">{entry.reason}</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="history-diff">
|
|
{selectedEntry && (
|
|
<DiffViewer
|
|
oldContent={selectedEntry.oldContent}
|
|
newContent={selectedEntry.newContent}
|
|
/>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|