import { useState, useEffect, useRef } from "react"; import type { FileVersionSummary, FileVersion, VersionSource } from "../../lib/api"; interface VersionHistoryDropdownProps { currentVersion: number; versions: FileVersionSummary[]; loading: boolean; selectedVersion: FileVersion | null; loadingVersion: boolean; onSelectVersion: (version: number) => void; onRestoreVersion: (version: number) => void; onClearSelection: () => void; restoring: boolean; } function formatDate(dateString: string): string { const date = new Date(dateString); return date.toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); } function getSourceLabel(source: VersionSource): string { switch (source) { case "user": return "User"; case "llm": return "AI"; case "system": return "System"; } } function getSourceColor(source: VersionSource): string { switch (source) { case "user": return "text-blue-400"; case "llm": return "text-purple-400"; case "system": return "text-gray-400"; } } export function VersionHistoryDropdown({ currentVersion, versions, loading, selectedVersion, loadingVersion, onSelectVersion, onRestoreVersion, onClearSelection, restoring, }: VersionHistoryDropdownProps) { const [isOpen, setIsOpen] = useState(false); const [showConfirm, setShowConfirm] = useState(false); const [versionToRestore, setVersionToRestore] = useState(null); const dropdownRef = useRef(null); // Close dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } } document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const handleVersionClick = (version: number) => { if (version === currentVersion) return; onSelectVersion(version); setIsOpen(false); }; const handleRestoreClick = (version: number) => { setVersionToRestore(version); setShowConfirm(true); }; const handleConfirmRestore = () => { if (versionToRestore !== null) { onRestoreVersion(versionToRestore); } setShowConfirm(false); setVersionToRestore(null); }; const handleCancelRestore = () => { setShowConfirm(false); setVersionToRestore(null); onClearSelection(); }; // If showing the selected version preview if (selectedVersion) { return (
Viewing Version v{selectedVersion.version} ({getSourceLabel(selectedVersion.source)})
{formatDate(selectedVersion.createdAt)} {selectedVersion.changeDescription && ( - {selectedVersion.changeDescription} )}
{/* Preview of version content */}
{selectedVersion.body.length === 0 ? (
No content
) : (
{selectedVersion.body.map((element, index) => (
{element.type === "heading" && (
{"#".repeat(element.level)} {element.text}
)} {element.type === "paragraph" && (
{element.text}
)} {element.type === "chart" && (
[Chart: {element.title || element.chartType}]
)} {element.type === "image" && (
[Image: {element.alt || element.src}]
)}
))}
)}
{/* Restore button */} {!showConfirm ? ( ) : (
Are you sure you want to restore to version {versionToRestore}?
This will create a new version with the content from v{versionToRestore}. Your current changes will be preserved as a separate version.
)}
); } return (
{isOpen && (
Version History
{loading ? (
Loading...
) : versions.length === 0 ? (
No versions found
) : (
{versions.map((version) => ( ))}
)}
)}
); }