import { useState, useEffect } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Typography, Box, LinearProgress, Alert, TextField, IconButton, Tooltip, Tabs, Tab, List, ListItem, ListItemText, Divider, Chip, } from '@mui/material'; import { Edit, Save, Close, Refresh, Delete, Restore, Visibility, History, } from '@mui/icons-material'; import Markdown from 'react-markdown'; import type { Idea, SpecificationHistoryItem } from '../../types/idea'; interface SpecificationModalProps { open: boolean; onClose: () => void; idea: Idea | null; specification: string | null; isLoading: boolean; error: Error | null; onSave: (specification: string) => void; isSaving: boolean; onRegenerate: () => void; history: SpecificationHistoryItem[]; isHistoryLoading: boolean; onDeleteHistoryItem: (historyId: string) => void; onRestoreFromHistory: (historyId: string) => void; isRestoring: boolean; } interface TabPanelProps { children?: React.ReactNode; index: number; value: number; } function TabPanel({ children, value, index }: TabPanelProps) { return ( ); } export function SpecificationModal({ open, onClose, idea, specification, isLoading, error, onSave, isSaving, onRegenerate, history, isHistoryLoading, onDeleteHistoryItem, onRestoreFromHistory, isRestoring, }: SpecificationModalProps) { const [isEditing, setIsEditing] = useState(false); const [editedText, setEditedText] = useState(''); const [tabIndex, setTabIndex] = useState(0); const [viewingHistoryItem, setViewingHistoryItem] = useState(null); // Сбрасываем состояние при открытии/закрытии useEffect(() => { if (open && specification) { setEditedText(specification); setIsEditing(false); setTabIndex(0); setViewingHistoryItem(null); } }, [open, specification]); const handleEdit = () => { setEditedText(specification ?? ''); setIsEditing(true); }; const handleCancel = () => { setEditedText(specification ?? ''); setIsEditing(false); }; const handleSave = () => { onSave(editedText); setIsEditing(false); }; const handleRegenerate = () => { setViewingHistoryItem(null); setTabIndex(0); onRegenerate(); }; const handleViewHistoryItem = (item: SpecificationHistoryItem) => { setViewingHistoryItem(item); }; const handleCloseHistoryView = () => { setViewingHistoryItem(null); }; const handleRestoreFromHistory = (historyId: string) => { onRestoreFromHistory(historyId); setViewingHistoryItem(null); setTabIndex(0); }; const formatDate = (dateString: string | null) => { if (!dateString) return ''; return new Date(dateString).toLocaleString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }); }; const hasHistory = history.length > 0; return ( Техническое задание {idea && ( {idea.title} )} {specification && !isLoading && !isEditing && !viewingHistoryItem && ( <> )} {/* Табы появляются только если есть история */} {hasHistory && !isEditing && !viewingHistoryItem && ( setTabIndex(newValue)} sx={{ px: 3, borderBottom: 1, borderColor: 'divider' }} > История ({history.length}) } data-testid="specification-tab-history" /> )} {/* Просмотр исторического ТЗ */} {viewingHistoryItem && ( Версия от {formatDate(viewingHistoryItem.createdAt)} handleRestoreFromHistory(viewingHistoryItem.id) } disabled={isRestoring} data-testid="specification-restore-button" > {viewingHistoryItem.ideaDescriptionSnapshot && ( Описание идеи на момент генерации:{' '} {viewingHistoryItem.ideaDescriptionSnapshot} )} {viewingHistoryItem.specification} )} {/* Основной контент (не историческая версия) */} {!viewingHistoryItem && ( <> {isLoading && ( Генерируем техническое задание... )} {error && ( {error.message || 'Не удалось сгенерировать ТЗ'} )} {!isLoading && !error && isEditing && ( setEditedText(e.target.value)} placeholder="Введите техническое задание..." data-testid="specification-textarea" sx={{ '& .MuiInputBase-input': { fontFamily: 'monospace', fontSize: '0.875rem', }, }} /> )} {!isLoading && !error && !isEditing && specification && ( {idea?.specificationGeneratedAt && ( Сгенерировано: {formatDate(idea.specificationGeneratedAt)} )} {specification} )} {isHistoryLoading ? ( ) : history.length === 0 ? ( История пуста ) : ( {history.map((item, index) => ( {index > 0 && } handleViewHistoryItem(item)} data-testid={`specification-history-view-${String(index)}`} > handleRestoreFromHistory(item.id) } disabled={isRestoring} data-testid={`specification-history-restore-${String(index)}`} > onDeleteHistoryItem(item.id)} data-testid={`specification-history-delete-${String(index)}`} > } > {formatDate(item.createdAt)} {item.ideaDescriptionSnapshot && ( )} } secondary={ {item.specification.slice(0, 150)}... } /> ))} )} )} {isEditing ? ( <> ) : viewingHistoryItem ? ( ) : ( )} ); }