"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: () => (
Загружаем предпросмотр...
),
},
);
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 =
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 (
);
}
return (
);
};
return (
{/* Header with Title and Actions */}
{/* Title Row */}
{document.title}
{/* Quick Actions */}
{onEditMetadata && (
)}
{document.file_url && (
<>
Скачать
>
)}
{/* Metadata Row - Always visible */}
{document.is_regulation && (
Регламент
)}
{document.file_name && (
{document.file_name}
{document.file_size && (
({formatFileSize(document.file_size)})
)}
)}
{formatDate(document.uploaded_at || document.created_at)}
{document.uploaded_by && (
{document.uploaded_by.last_name} {document.uploaded_by.first_name}
)}
{/* Mobile Tabs Navigation */}
{/* Content Area */}
{/* Desktop Layout: Side-by-side */}
{/* Preview Panel (Left) */}
{documentHasFile && (
{renderPreview()}
)}
{/* Info Panel (Right) */}
{!(documentHasFile && isFullscreen) && (
{/* Desktop Tabs */}
{/* Desktop Tab Content */}
{desktopActiveTab === "info" && (
{/* Description */}
Описание
{document.description || "Описание отсутствует"}
{/* Author & Dates */}
Информация
Автор
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Не указан"}
Создан
{formatDate(document.uploaded_at || document.created_at)}
{document.modified_at && (
Изменен
{formatDate(document.modified_at)}
)}
{/* Folder Location */}
{document.folder_path && (
Расположение
{document.folder_path.split(" / ").map((folder, index, arr) => (
{folder}
{index < arr.length - 1 && (
)}
))}
)}
{/* Tags */}
{document.tags && document.tags.length > 0 && (
Теги
{document.tags.map((tag) => (
{tag.name}
))}
)}
{/* Recipients */}
{(document.sent_to_all ||
(document.departments && document.departments.length > 0) ||
(document.recipients && document.recipients.length > 0)) && (
Получатели
{document.sent_to_all && (
Все сотрудники
)}
{document.departments && document.departments.length > 0 && (
Отделы ({document.departments.length})
{document.departments.map((dept) => (
{dept.name}
))}
)}
{document.recipients && document.recipients.length > 0 && (
Получатели ({document.recipients.length})
{document.recipients.slice(0, 5).map((recipient) => (
{recipient.last_name} {recipient.first_name}
))}
{document.recipients.length > 5 && (
... и ещё {document.recipients.length - 5}
)}
)}
)}
)}
{desktopActiveTab === "activity" && (
История активности
Создан
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Система"}{" "}
• {formatDate(document.uploaded_at || document.created_at)}
История изменений будет доступна после интеграции с django-reversion API
)}
{desktopActiveTab === "acknowledgements" && (
{document.acknowledgement_required ? (
<>
{onViewReport && (
Подтверждение прочтения
)}
onUpdate?.()}
showAction={false}
/>
>
) : (
Для этого документа не требуется подтверждение ознакомления
)}
)}
{desktopActiveTab === "comments" && (
)}
{desktopActiveTab === "related" && (
onNavigateToRelated?.(docId)}
/>
)}
)}
{/* Mobile Layout: Tabs */}
{currentActiveTab === "preview" && (
{renderPreview()}
)}
{currentActiveTab === "info" && (
{/* Description */}
Описание
{document.description || "Описание отсутствует"}
{/* Author & Dates */}
Информация
Автор
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Не указан"}
Создан
{formatDate(document.uploaded_at || document.created_at)}
{document.modified_at && (
Изменен
{formatDate(document.modified_at)}
)}
{/* Folder Location */}
{document.folder_path && (
Расположение
{document.folder_path.split(" / ").map((folder, index, arr) => (
{folder}
{index < arr.length - 1 && (
)}
))}
)}
{/* Tags */}
{document.tags && document.tags.length > 0 && (
Теги
{document.tags.map((tag) => (
{tag.name}
))}
)}
{/* Recipients */}
{(document.sent_to_all ||
(document.departments && document.departments.length > 0) ||
(document.recipients && document.recipients.length > 0)) && (
Получатели
{document.sent_to_all && (
Все сотрудники
)}
{document.departments && document.departments.length > 0 && (
Отделы ({document.departments.length})
{document.departments.map((dept) => (
{dept.name}
))}
)}
{document.recipients && document.recipients.length > 0 && (
Получатели ({document.recipients.length})
{document.recipients.slice(0, 5).map((recipient) => (
{recipient.last_name} {recipient.first_name}
))}
{document.recipients.length > 5 && (
... и ещё {document.recipients.length - 5}
)}
)}
)}
)}
{currentActiveTab === "activity" && (
История активности
Создан
{document.uploaded_by
? `${document.uploaded_by.last_name} ${document.uploaded_by.first_name}`
: "Система"}{" "}
• {formatDate(document.uploaded_at || document.created_at)}
История изменений будет доступна после интеграции с django-reversion API
)}
{currentActiveTab === "acknowledgements" && (
{document.acknowledgement_required ? (
<>
{onViewReport && (
Подтверждение прочтения
)}
onUpdate?.()}
showAction={false}
/>
>
) : (
Для этого документа не требуется подтверждение ознакомления
)}
)}
{currentActiveTab === "comments" && (
)}
{currentActiveTab === "related" && (
onNavigateToRelated?.(docId)}
/>
)}
{showPersistentAcknowledgeAction && (
onUpdate?.()}
className="pointer-events-auto w-full shadow-[0_12px_32px_rgba(0,0,0,0.35)] sm:w-auto sm:min-w-[220px]"
/>
)}
);
}