Corp/frontend/src/components/documents/DocumentDetailModal.tsx

856 lines
40 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import dynamic from "next/dynamic";
import { Modal } from "@/components/ui/Modal";
import type { Document } from "@/types/api";
import {
FileText,
User,
Calendar,
HardDrive,
FolderOpen,
Users,
Building2,
Tag,
Clock,
CheckCircle,
Eye,
Download,
ChevronRight,
Activity,
Maximize2,
Minimize2,
Info,
Edit,
MessageSquare,
Link2,
ScrollText,
} from "lucide-react";
import { DocumentAcknowledgeButton, DocumentAcknowledgement } from "./DocumentAcknowledgement";
import { DocumentComments } from "./DocumentComments";
import { DocumentRelated } from "./DocumentRelated";
import { DocumentTaskLinks } from "./DocumentTaskLinks";
const DocumentPreviewPane = dynamic(
() => import("./DocumentPreview").then((mod) => mod.DocumentPreviewPane),
{
ssr: false,
loading: () => (
<div className="app-surface-muted flex h-full items-center justify-center">
<p className="app-text-muted text-sm">Загружаем предпросмотр...</p>
</div>
),
},
);
interface DocumentDetailModalProps {
document: Document | null;
isOpen: boolean;
initialTab?: TabType;
onClose: () => void;
onUpdate?: () => void;
onEditMetadata?: () => void;
onViewReport?: () => void;
onNavigateToRelated?: (docId: number) => void;
}
type TabType = "preview" | "info" | "activity" | "acknowledgements" | "comments" | "related";
export function DocumentDetailModal({
document,
isOpen,
initialTab,
onClose,
onUpdate,
onEditMetadata,
onViewReport,
onNavigateToRelated,
}: DocumentDetailModalProps) {
const [activeTabState, setActiveTabState] = useState<{ documentId: number | null; value: TabType }>({
documentId: null,
value: "preview",
});
const [fullscreenState, setFullscreenState] = useState<{ documentId: number | null; value: boolean }>({
documentId: null,
value: false,
});
const documentId = document?.id ?? null;
const documentHasFile = Boolean(document?.file_url);
const documentRequiresAcknowledgement = Boolean(document?.acknowledgement_required);
const acknowledgementRequiredForUser = Boolean(
document?.acknowledgement_required_for_user ?? document?.acknowledgement_required,
);
const showPersistentAcknowledgeAction = acknowledgementRequiredForUser && !document?.is_acknowledged;
if (!document) return null;
const formatDate = (date: string) => {
return new Date(date).toLocaleDateString("ru-RU", {
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
};
const formatFileSize = (bytes: number) => {
if (bytes < 1024) return `${bytes} Б`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} КБ`;
return `${(bytes / 1024 / 1024).toFixed(2)} МБ`;
};
const tabs = [
...(documentHasFile ? [{ id: "preview" as TabType, label: "Предпросмотр", icon: Eye }] : []),
{ id: "info" as TabType, label: "Информация", icon: Info },
{ id: "activity" as TabType, label: "Активность", icon: Activity },
...(documentRequiresAcknowledgement ? [{ id: "acknowledgements" as TabType, label: "Ознакомления", icon: CheckCircle }] : []),
{ id: "comments" as TabType, label: "Комментарии", icon: MessageSquare },
{ id: "related" as TabType, label: "Связанные", icon: Link2 },
];
const defaultTab: TabType = initialTab && tabs.some((tab) => tab.id === initialTab)
? initialTab
: documentHasFile
? "preview"
: "info";
const activeTab: TabType = activeTabState.documentId === documentId
? activeTabState.value
: defaultTab;
const currentActiveTab = tabs.some((tab) => tab.id === activeTab) ? activeTab : defaultTab;
const desktopActiveTab: Exclude<TabType, "preview"> =
currentActiveTab === "preview" ? "info" : currentActiveTab;
const isFullscreen = fullscreenState.documentId === documentId ? fullscreenState.value : false;
const detailTabs = tabs.filter((tab) => tab.id !== "preview");
const setDocumentActiveTab = (value: TabType) => {
setActiveTabState({ documentId, value });
};
const setDocumentFullscreen = (value: boolean) => {
setFullscreenState({ documentId, value });
};
const renderPreview = () => {
if (!document.file_url) {
return (
<div className="app-surface-muted flex h-full items-center justify-center">
<div className="text-center">
<FileText size={64} className="app-text-muted mx-auto" />
<p className="app-text-muted mt-4 text-sm font-medium">Файл не прикреплен</p>
</div>
</div>
);
}
return (
<DocumentPreviewPane
fileUrl={document.file_url}
fileName={document.file_name || document.title}
/>
);
};
return (
<Modal
isOpen={isOpen}
onClose={onClose}
size="full"
showCloseButton
noPadding
className="relative flex h-[95vh] flex-col sm:h-[90vh]"
>
<div className="mx-4 flex h-full min-h-0 flex-col sm:mx-6">
{/* Header with Title and Actions */}
<div className="app-divider app-header shrink-0 border-b px-4 py-4 sm:px-6">
<div className="flex flex-col gap-3">
{/* Title Row */}
<div className="flex items-start justify-between gap-4">
<div className="min-w-0 flex-1">
<h2 className="text-lg font-semibold text-[var(--foreground)] sm:text-xl">{document.title}</h2>
</div>
{/* Quick Actions */}
<div className="flex shrink-0 items-center gap-2">
{onEditMetadata && (
<button
onClick={onEditMetadata}
className="app-selected app-accent-text inline-flex items-center gap-2 rounded-lg p-2 text-sm font-medium transition hover:opacity-90"
title="Редактировать метаданные"
>
<Edit size={16} />
<span className="hidden sm:inline">Редактировать</span>
</button>
)}
{document.file_url && (
<>
<a
href={document.file_url}
download
className="app-action-secondary inline-flex items-center gap-2 rounded-lg p-2 text-sm font-medium"
title="Скачать"
>
<Download size={16} />
<span className="hidden sm:inline">Скачать</span>
</a>
<button
onClick={() => setDocumentFullscreen(!isFullscreen)}
className="app-action-secondary hidden items-center gap-2 rounded-lg p-2 text-sm font-medium lg:inline-flex"
title={isFullscreen ? "Обычный режим" : "Полный экран"}
>
{isFullscreen ? <Minimize2 size={16} /> : <Maximize2 size={16} />}
</button>
</>
)}
</div>
</div>
{/* Metadata Row - Always visible */}
<div className="app-text-muted flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
{document.is_regulation && (
<div className="app-selected app-accent-text flex items-center gap-1.5 rounded-full px-2.5 py-1 font-medium">
<ScrollText size={14} className="shrink-0" />
<span>Регламент</span>
</div>
)}
{document.file_name && (
<div className="flex items-center gap-1.5">
<HardDrive size={14} className="app-text-muted shrink-0" />
<span className="truncate font-medium">{document.file_name}</span>
{document.file_size && (
<span className="app-text-muted shrink-0">({formatFileSize(document.file_size)})</span>
)}
</div>
)}
<div className="flex items-center gap-1.5">
<Calendar size={14} className="app-text-muted shrink-0" />
<span>{formatDate(document.uploaded_at || document.created_at)}</span>
</div>
{document.uploaded_by && (
<div className="flex items-center gap-1.5">
<User size={14} className="app-text-muted shrink-0" />
<span>{document.uploaded_by.last_name} {document.uploaded_by.first_name}</span>
</div>
)}
</div>
</div>
</div>
{/* Mobile Tabs Navigation */}
<div className="app-divider app-surface-muted shrink-0 border-b px-4 sm:px-6 lg:hidden">
<nav className="app-tabs-scroll flex gap-1 overflow-x-auto overflow-y-hidden pb-1">
{tabs.map((tab) => {
const Icon = tab.icon;
const isActive = currentActiveTab === tab.id;
return (
<button
key={tab.id}
onClick={() => setDocumentActiveTab(tab.id)}
className={`flex shrink-0 items-center gap-2 whitespace-nowrap border-b-2 px-4 py-3 text-sm font-medium transition ${
isActive
? "border-[var(--accent-primary)] text-[var(--accent-primary-strong)]"
: "border-transparent text-[var(--muted-foreground)] hover:border-[var(--border-strong)] hover:text-[var(--foreground)]"
}`}
>
<Icon size={16} />
<span className="whitespace-nowrap">{tab.label}</span>
</button>
);
})}
</nav>
</div>
{/* Content Area */}
<div className="min-h-0 flex-1 overflow-hidden">
{/* Desktop Layout: Side-by-side */}
<div className="hidden h-full lg:flex">
{/* Preview Panel (Left) */}
{documentHasFile && (
<div className={`${isFullscreen ? "w-full" : "w-3/5"} min-h-0 shrink-0 overflow-hidden border-r border-[var(--border-subtle)] transition-all`}>
{renderPreview()}
</div>
)}
{/* Info Panel (Right) */}
{!(documentHasFile && isFullscreen) && (
<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
{/* Desktop Tabs */}
<div className="app-divider app-surface-muted shrink-0 border-b px-6">
<nav className="app-tabs-scroll flex gap-1 overflow-x-auto overflow-y-hidden pb-1">
{detailTabs.map((tab) => {
const Icon = tab.icon;
const isActive = desktopActiveTab === tab.id;
return (
<button
key={tab.id}
onClick={() => setDocumentActiveTab(tab.id)}
className={`flex shrink-0 items-center gap-2 whitespace-nowrap border-b-2 px-4 py-3 text-sm font-medium transition ${
isActive
? "border-[var(--accent-primary)] text-[var(--accent-primary-strong)]"
: "border-transparent text-[var(--muted-foreground)] hover:border-[var(--border-strong)] hover:text-[var(--foreground)]"
}`}
>
<Icon size={16} />
{tab.label}
</button>
);
})}
</nav>
</div>
{/* Desktop Tab Content */}
<div className="min-h-0 flex-1 overflow-y-auto bg-[var(--surface-secondary)]">
{desktopActiveTab === "info" && (
<div className="p-6">
<div className="space-y-4">
{/* Description */}
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Описание
</h3>
<p className="app-text-wrap app-text-muted text-sm leading-relaxed">
{document.description || "Описание отсутствует"}
</p>
</div>
{/* Author & Dates */}
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Информация
</h3>
<div className="space-y-3">
<div className="flex items-start gap-3">
<div className="app-selected app-accent-text rounded-lg p-2">
<User size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Автор</p>
<p className="truncate text-sm font-medium text-[var(--foreground)]">
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Не указан"}
</p>
</div>
</div>
<div className="flex items-start gap-3">
<div className="app-feedback-success rounded-lg p-2">
<Calendar size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Создан</p>
<p className="text-sm font-medium text-[var(--foreground)]">
{formatDate(document.uploaded_at || document.created_at)}
</p>
</div>
</div>
{document.modified_at && (
<div className="flex items-start gap-3">
<div className="app-feedback-warning rounded-lg p-2">
<Clock size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Изменен</p>
<p className="text-sm font-medium text-[var(--foreground)]">
{formatDate(document.modified_at)}
</p>
</div>
</div>
)}
</div>
</div>
{/* Folder Location */}
{document.folder_path && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Расположение
</h3>
<div className="flex items-center gap-2 text-sm">
<FolderOpen size={16} className="app-accent-text shrink-0" />
<div className="flex min-w-0 flex-1 items-center gap-1 overflow-hidden">
{document.folder_path.split(" / ").map((folder, index, arr) => (
<div key={index} className="flex items-center gap-1">
<span className="truncate text-[var(--foreground)]">{folder}</span>
{index < arr.length - 1 && (
<ChevronRight size={14} className="app-text-muted shrink-0" />
)}
</div>
))}
</div>
</div>
</div>
)}
{/* Tags */}
{document.tags && document.tags.length > 0 && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Теги
</h3>
<div className="flex flex-wrap gap-2">
{document.tags.map((tag) => (
<span
key={tag.id}
className="app-badge inline-flex items-center gap-1 px-3 py-1 text-xs font-medium"
>
<Tag size={12} />
{tag.name}
</span>
))}
</div>
</div>
)}
{/* Recipients */}
{(document.sent_to_all ||
(document.departments && document.departments.length > 0) ||
(document.recipients && document.recipients.length > 0)) && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Получатели
</h3>
<div className="space-y-3">
{document.sent_to_all && (
<div className="app-selected app-accent-text flex items-center gap-2 rounded-lg px-3 py-2 text-xs font-medium">
<CheckCircle size={14} />
Все сотрудники
</div>
)}
{document.departments && document.departments.length > 0 && (
<div>
<div className="app-text-muted mb-2 flex items-center gap-2 text-xs font-medium">
<Building2 size={14} />
Отделы ({document.departments.length})
</div>
<div className="space-y-1">
{document.departments.map((dept) => (
<div
key={dept.id}
className="app-surface-muted flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-[var(--foreground)]"
>
<Building2 size={12} className="app-text-muted" />
{dept.name}
</div>
))}
</div>
</div>
)}
{document.recipients && document.recipients.length > 0 && (
<div>
<div className="app-text-muted mb-2 flex items-center gap-2 text-xs font-medium">
<Users size={14} />
Получатели ({document.recipients.length})
</div>
<div className="max-h-40 space-y-1 overflow-y-auto">
{document.recipients.slice(0, 5).map((recipient) => (
<div
key={recipient.id}
className="app-surface-muted flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-[var(--foreground)]"
>
<User size={12} className="app-text-muted" />
{recipient.last_name} {recipient.first_name}
</div>
))}
{document.recipients.length > 5 && (
<div className="app-text-muted px-3 py-2 text-xs">
... и ещё {document.recipients.length - 5}
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
{desktopActiveTab === "activity" && (
<div className="p-6">
<div className="app-surface rounded-xl p-6">
<h3 className="mb-4 text-lg font-semibold text-[var(--foreground)]">История активности</h3>
<div className="space-y-4">
<div className="flex gap-4">
<div className="flex flex-col items-center">
<div className="app-selected app-accent-text flex h-10 w-10 items-center justify-center rounded-full">
<Activity size={20} />
</div>
<div className="w-px flex-1 bg-[var(--border-subtle)]"></div>
</div>
<div className="flex-1 pb-8">
<p className="text-sm font-medium text-[var(--foreground)]">Создан</p>
<p className="app-text-muted mt-1 text-xs">
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Система"}{" "}
• {formatDate(document.uploaded_at || document.created_at)}
</p>
</div>
</div>
<div className="app-surface-muted rounded-lg p-4 text-center">
<Activity size={32} className="app-text-muted mx-auto" />
<p className="app-text-muted mt-2 text-sm">
История изменений будет доступна после интеграции с django-reversion API
</p>
</div>
</div>
</div>
</div>
)}
{desktopActiveTab === "acknowledgements" && (
<div className="p-6">
<div className="app-surface rounded-xl p-6">
{document.acknowledgement_required ? (
<>
{onViewReport && (
<div className="mb-4 flex items-center justify-between">
<h3 className="text-sm font-medium text-[var(--foreground)]">Подтверждение прочтения</h3>
<button
onClick={onViewReport}
className="app-selected app-accent-text inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs font-medium hover:opacity-90"
>
Посмотреть ведомость
</button>
</div>
)}
<DocumentAcknowledgement
document={document}
onAcknowledge={() => onUpdate?.()}
showAction={false}
/>
</>
) : (
<div className="py-12 text-center">
<CheckCircle size={48} className="app-text-muted mx-auto" />
<p className="app-text-muted mt-4 text-sm">
Для этого документа не требуется подтверждение ознакомления
</p>
</div>
)}
</div>
</div>
)}
{desktopActiveTab === "comments" && (
<div className="p-6">
<div className="app-surface rounded-xl p-6">
<DocumentComments
documentId={document.id}
onCommentsChanged={() => onUpdate?.()}
/>
</div>
</div>
)}
{desktopActiveTab === "related" && (
<div className="p-6">
<div className="space-y-4">
<div className="app-surface rounded-xl p-6">
<DocumentTaskLinks document={document} />
</div>
<div className="app-surface rounded-xl p-6">
<DocumentRelated
documentId={document.id}
onNavigate={(docId) => onNavigateToRelated?.(docId)}
/>
</div>
</div>
</div>
)}
</div>
</div>
)}
</div>
{/* Mobile Layout: Tabs */}
<div className="h-full overflow-y-auto bg-[var(--surface-secondary)] lg:hidden">
{currentActiveTab === "preview" && (
<div className="h-full min-h-[400px]">{renderPreview()}</div>
)}
{currentActiveTab === "info" && (
<div className="p-4 sm:p-6">
<div className="space-y-4">
{/* Description */}
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Описание
</h3>
<p className="app-text-wrap app-text-muted text-sm leading-relaxed">
{document.description || "Описание отсутствует"}
</p>
</div>
{/* Author & Dates */}
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Информация
</h3>
<div className="space-y-3">
<div className="flex items-start gap-3">
<div className="app-selected app-accent-text rounded-lg p-2">
<User size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Автор</p>
<p className="truncate text-sm font-medium text-[var(--foreground)]">
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Не указан"}
</p>
</div>
</div>
<div className="flex items-start gap-3">
<div className="app-feedback-success rounded-lg p-2">
<Calendar size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Создан</p>
<p className="text-sm font-medium text-[var(--foreground)]">
{formatDate(document.uploaded_at || document.created_at)}
</p>
</div>
</div>
{document.modified_at && (
<div className="flex items-start gap-3">
<div className="app-feedback-warning rounded-lg p-2">
<Clock size={16} />
</div>
<div className="min-w-0 flex-1">
<p className="app-text-muted text-xs">Изменен</p>
<p className="text-sm font-medium text-[var(--foreground)]">
{formatDate(document.modified_at)}
</p>
</div>
</div>
)}
</div>
</div>
{/* Folder Location */}
{document.folder_path && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Расположение
</h3>
<div className="flex items-center gap-2 text-sm">
<FolderOpen size={16} className="app-accent-text shrink-0" />
<div className="flex min-w-0 flex-1 flex-col gap-1 overflow-hidden">
{document.folder_path.split(" / ").map((folder, index, arr) => (
<div key={index} className="flex items-center gap-1">
<span className="truncate text-[var(--foreground)]">{folder}</span>
{index < arr.length - 1 && (
<ChevronRight size={14} className="app-text-muted shrink-0" />
)}
</div>
))}
</div>
</div>
</div>
)}
{/* Tags */}
{document.tags && document.tags.length > 0 && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Теги
</h3>
<div className="flex flex-wrap gap-2">
{document.tags.map((tag) => (
<span
key={tag.id}
className="app-badge inline-flex items-center gap-1 px-3 py-1 text-xs font-medium"
>
<Tag size={12} />
{tag.name}
</span>
))}
</div>
</div>
)}
{/* Recipients */}
{(document.sent_to_all ||
(document.departments && document.departments.length > 0) ||
(document.recipients && document.recipients.length > 0)) && (
<div className="app-surface rounded-xl p-4">
<h3 className="app-text-muted mb-3 text-xs font-semibold uppercase tracking-wide">
Получатели
</h3>
<div className="space-y-3">
{document.sent_to_all && (
<div className="app-selected app-accent-text flex items-center gap-2 rounded-lg px-3 py-2 text-xs font-medium">
<CheckCircle size={14} />
Все сотрудники
</div>
)}
{document.departments && document.departments.length > 0 && (
<div>
<div className="app-text-muted mb-2 flex items-center gap-2 text-xs font-medium">
<Building2 size={14} />
Отделы ({document.departments.length})
</div>
<div className="space-y-1">
{document.departments.map((dept) => (
<div
key={dept.id}
className="app-surface-muted flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-[var(--foreground)]"
>
<Building2 size={12} className="app-text-muted" />
{dept.name}
</div>
))}
</div>
</div>
)}
{document.recipients && document.recipients.length > 0 && (
<div>
<div className="app-text-muted mb-2 flex items-center gap-2 text-xs font-medium">
<Users size={14} />
Получатели ({document.recipients.length})
</div>
<div className="max-h-40 space-y-1 overflow-y-auto">
{document.recipients.slice(0, 5).map((recipient) => (
<div
key={recipient.id}
className="app-surface-muted flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-[var(--foreground)]"
>
<User size={12} className="app-text-muted" />
{recipient.last_name} {recipient.first_name}
</div>
))}
{document.recipients.length > 5 && (
<div className="app-text-muted px-3 py-2 text-xs">
... и ещё {document.recipients.length - 5}
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
{currentActiveTab === "activity" && (
<div className="p-4 sm:p-6">
<div className="app-surface rounded-xl p-4 sm:p-6">
<h3 className="mb-4 text-lg font-semibold text-[var(--foreground)]">История активности</h3>
<div className="space-y-4">
<div className="flex gap-4">
<div className="flex flex-col items-center">
<div className="app-selected app-accent-text flex h-10 w-10 items-center justify-center rounded-full">
<Activity size={20} />
</div>
<div className="w-px flex-1 bg-[var(--border-subtle)]"></div>
</div>
<div className="flex-1 pb-8">
<p className="text-sm font-medium text-[var(--foreground)]">Создан</p>
<p className="app-text-muted mt-1 text-xs">
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Система"}{" "}
• {formatDate(document.uploaded_at || document.created_at)}
</p>
</div>
</div>
<div className="app-surface-muted rounded-lg p-4 text-center">
<Activity size={32} className="app-text-muted mx-auto" />
<p className="app-text-muted mt-2 text-sm">
История изменений будет доступна после интеграции с django-reversion API
</p>
</div>
</div>
</div>
</div>
)}
{currentActiveTab === "acknowledgements" && (
<div className="p-4 sm:p-6">
<div className="app-surface rounded-xl p-4 sm:p-6">
{document.acknowledgement_required ? (
<>
{onViewReport && (
<div className="mb-4 flex items-center justify-between">
<h3 className="text-sm font-medium text-[var(--foreground)]">Подтверждение прочтения</h3>
<button
onClick={onViewReport}
className="app-selected app-accent-text inline-flex items-center gap-1 rounded-lg px-3 py-1.5 text-xs font-medium hover:opacity-90"
>
Посмотреть ведомость
</button>
</div>
)}
<DocumentAcknowledgement
document={document}
onAcknowledge={() => onUpdate?.()}
showAction={false}
/>
</>
) : (
<div className="py-12 text-center">
<CheckCircle size={48} className="app-text-muted mx-auto" />
<p className="app-text-muted mt-4 text-sm">
Для этого документа не требуется подтверждение ознакомления
</p>
</div>
)}
</div>
</div>
)}
{currentActiveTab === "comments" && (
<div className="p-4 sm:p-6">
<div className="app-surface rounded-xl p-4 sm:p-6">
<DocumentComments
documentId={document.id}
onCommentsChanged={() => onUpdate?.()}
/>
</div>
</div>
)}
{currentActiveTab === "related" && (
<div className="p-4 sm:p-6">
<div className="space-y-4">
<div className="app-surface rounded-xl p-4 sm:p-6">
<DocumentTaskLinks document={document} />
</div>
<div className="app-surface rounded-xl p-4 sm:p-6">
<DocumentRelated
documentId={document.id}
onNavigate={(docId) => onNavigateToRelated?.(docId)}
/>
</div>
</div>
</div>
)}
</div>
</div>
{showPersistentAcknowledgeAction && (
<div className="pointer-events-none absolute inset-x-4 bottom-4 z-30 flex justify-end sm:inset-x-6 sm:bottom-6">
<DocumentAcknowledgeButton
document={document}
onAcknowledge={() => onUpdate?.()}
className="pointer-events-auto w-full shadow-[0_12px_32px_rgba(0,0,0,0.35)] sm:w-auto sm:min-w-[220px]"
/>
</div>
)}
</div>
</Modal>
);
}