206 lines
6.7 KiB
TypeScript
206 lines
6.7 KiB
TypeScript
|
|
import React from "react";
|
|||
|
|
import {
|
|||
|
|
FaTimes,
|
|||
|
|
FaDownload,
|
|||
|
|
FaFileAlt,
|
|||
|
|
FaFilePdf,
|
|||
|
|
FaFileWord,
|
|||
|
|
FaFileExcel,
|
|||
|
|
FaFilePowerpoint,
|
|||
|
|
FaFileImage,
|
|||
|
|
} from "react-icons/fa";
|
|||
|
|
import { PsProjectDocument } from "../../../types/ps";
|
|||
|
|
import dayjs from "dayjs";
|
|||
|
|
import { getPsDocumentTypeText } from "../../../utils/erp";
|
|||
|
|
|
|||
|
|
interface DocumentViewerModalProps {
|
|||
|
|
isOpen: boolean;
|
|||
|
|
onClose: () => void;
|
|||
|
|
document: PsProjectDocument | null;
|
|||
|
|
onDownload?: (document: PsProjectDocument) => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const DocumentViewerModal: React.FC<DocumentViewerModalProps> = ({
|
|||
|
|
isOpen,
|
|||
|
|
onClose,
|
|||
|
|
document,
|
|||
|
|
onDownload,
|
|||
|
|
}) => {
|
|||
|
|
const getFileIcon = (fileName: string) => {
|
|||
|
|
const extension = fileName.toLowerCase().split(".").pop();
|
|||
|
|
|
|||
|
|
switch (extension) {
|
|||
|
|
case "pdf":
|
|||
|
|
return <FaFilePdf className="w-8 h-8 text-red-500" />;
|
|||
|
|
case "doc":
|
|||
|
|
case "docx":
|
|||
|
|
return <FaFileWord className="w-8 h-8 text-blue-500" />;
|
|||
|
|
case "xls":
|
|||
|
|
case "xlsx":
|
|||
|
|
return <FaFileExcel className="w-8 h-8 text-green-500" />;
|
|||
|
|
case "ppt":
|
|||
|
|
case "pptx":
|
|||
|
|
return <FaFilePowerpoint className="w-8 h-8 text-orange-500" />;
|
|||
|
|
case "jpg":
|
|||
|
|
case "jpeg":
|
|||
|
|
case "png":
|
|||
|
|
case "gif":
|
|||
|
|
return <FaFileImage className="w-8 h-8 text-purple-500" />;
|
|||
|
|
default:
|
|||
|
|
return <FaFileAlt className="w-8 h-8 text-gray-500" />;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const formatFileSize = (sizeInMB: number): string => {
|
|||
|
|
if (sizeInMB < 1) {
|
|||
|
|
return `${(sizeInMB * 1024).toFixed(0)} KB`;
|
|||
|
|
}
|
|||
|
|
return `${sizeInMB.toFixed(2)} MB`;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleDownload = () => {
|
|||
|
|
if (document && onDownload) {
|
|||
|
|
onDownload(document);
|
|||
|
|
} else if (document) {
|
|||
|
|
// Fallback: create a download link
|
|||
|
|
const link = window.document.createElement("a");
|
|||
|
|
link.href = document.filePath;
|
|||
|
|
link.download = document.documentName;
|
|||
|
|
link.click();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const isImageFile = (fileName: string): boolean => {
|
|||
|
|
const extension = fileName.toLowerCase().split(".").pop();
|
|||
|
|
return ["jpg", "jpeg", "png", "gif"].includes(extension || "");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const isPdfFile = (fileName: string): boolean => {
|
|||
|
|
const extension = fileName.toLowerCase().split(".").pop();
|
|||
|
|
return extension === "pdf";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (!isOpen || !document) return null;
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|||
|
|
<div className="bg-white rounded-lg w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col">
|
|||
|
|
{/* Header */}
|
|||
|
|
<div className="flex items-center justify-between p-3 border-b border-gray-200">
|
|||
|
|
<div className="flex items-center space-x-3">
|
|||
|
|
{getFileIcon(document.documentName)}
|
|||
|
|
<div>
|
|||
|
|
<h2 className="text-lg font-semibold text-gray-900">
|
|||
|
|
{document.documentName}
|
|||
|
|
</h2>
|
|||
|
|
<p className="text-sm text-gray-500">
|
|||
|
|
{getPsDocumentTypeText(document.documentType)} •{" "}
|
|||
|
|
{formatFileSize(document.fileSize)}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex items-center space-x-2">
|
|||
|
|
<button
|
|||
|
|
onClick={handleDownload}
|
|||
|
|
className="flex items-center space-x-2 px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
|||
|
|
>
|
|||
|
|
<FaDownload className="w-4 h-4" />
|
|||
|
|
<span>İndir</span>
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
onClick={onClose}
|
|||
|
|
className="text-gray-400 hover:text-gray-600 p-2"
|
|||
|
|
>
|
|||
|
|
<FaTimes className="w-4 h-4" />
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Document Info */}
|
|||
|
|
<div className="px-4 py-2 bg-gray-50 border-b border-gray-200">
|
|||
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
|
|||
|
|
<div>
|
|||
|
|
<span className="font-medium text-gray-700">Yükleyen:</span>
|
|||
|
|
<p className="text-gray-600">{document.uploadedBy}</p>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<span className="font-medium text-gray-700">
|
|||
|
|
Yüklenme Tarihi:
|
|||
|
|
</span>
|
|||
|
|
<p className="text-gray-600">
|
|||
|
|
{dayjs(document.uploadedAt).format("DD.MM.YYYY HH:mm")}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<span className="font-medium text-gray-700">Versiyon:</span>
|
|||
|
|
<p className="text-gray-600">v{document.version}</p>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<span className="font-medium text-gray-700">Dosya Boyutu:</span>
|
|||
|
|
<p className="text-gray-600">
|
|||
|
|
{formatFileSize(document.fileSize)}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Document Preview */}
|
|||
|
|
<div className="flex-1 p-3 overflow-auto">
|
|||
|
|
{isImageFile(document.documentName) ? (
|
|||
|
|
<div className="flex items-center justify-center h-full">
|
|||
|
|
<img
|
|||
|
|
src={document.filePath}
|
|||
|
|
alt={document.documentName}
|
|||
|
|
className="max-w-full max-h-full object-contain"
|
|||
|
|
onError={(e) => {
|
|||
|
|
const target = e.target as HTMLImageElement;
|
|||
|
|
target.style.display = "none";
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
) : isPdfFile(document.documentName) ? (
|
|||
|
|
<div className="h-full">
|
|||
|
|
<iframe
|
|||
|
|
src={document.filePath}
|
|||
|
|
className="w-full h-full border-0"
|
|||
|
|
title={document.documentName}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
) : (
|
|||
|
|
<div className="flex flex-col items-center justify-center h-full text-center">
|
|||
|
|
{getFileIcon(document.documentName)}
|
|||
|
|
<h3 className="mt-4 text-lg font-medium text-gray-900">
|
|||
|
|
Önizleme Mevcut Değil
|
|||
|
|
</h3>
|
|||
|
|
<p className="mt-2 text-sm text-gray-500">
|
|||
|
|
Bu dosya türü için önizleme desteklenmiyor.
|
|||
|
|
</p>
|
|||
|
|
<p className="text-sm text-gray-500">
|
|||
|
|
Dosyayı görüntülemek için indirin.
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Footer */}
|
|||
|
|
<div className="px-4 py-2 bg-gray-50 border-t border-gray-200">
|
|||
|
|
<div className="flex items-center justify-between">
|
|||
|
|
<div className="text-sm text-gray-500">
|
|||
|
|
Son güncelleme:{" "}
|
|||
|
|
{dayjs(document.uploadedAt).format("DD.MM.YYYY HH:mm")}
|
|||
|
|
</div>
|
|||
|
|
<button
|
|||
|
|
onClick={onClose}
|
|||
|
|
className="px-3 py-1 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50"
|
|||
|
|
>
|
|||
|
|
Kapat
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default DocumentViewerModal;
|