230 lines
7.1 KiB
TypeScript
230 lines
7.1 KiB
TypeScript
import React, { useState, useEffect } from 'react'
|
|
import {
|
|
Box,
|
|
Typography,
|
|
Paper,
|
|
IconButton,
|
|
Button,
|
|
Dialog,
|
|
DialogTitle,
|
|
DialogContent,
|
|
DialogActions,
|
|
CircularProgress,
|
|
Alert,
|
|
} from '@mui/material'
|
|
import {
|
|
PictureAsPdf,
|
|
Download,
|
|
Close,
|
|
ZoomIn,
|
|
ZoomOut,
|
|
NavigateBefore,
|
|
NavigateNext,
|
|
} from '@mui/icons-material'
|
|
import type { Document } from '../types'
|
|
|
|
interface FilePreviewProps {
|
|
document: Document
|
|
onClose: () => void
|
|
}
|
|
|
|
export const FilePreview: React.FC<FilePreviewProps> = ({ document, onClose }) => {
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [page, setPage] = useState(1)
|
|
const [scale, setScale] = useState(1.0)
|
|
const [numPages, setNumPages] = useState(0)
|
|
|
|
useEffect(() => {
|
|
setLoading(true)
|
|
setError(null)
|
|
setPage(1)
|
|
setScale(1.0)
|
|
|
|
// Simuler le chargement du PDF
|
|
const timer = setTimeout(() => {
|
|
setNumPages(3) // Simuler 3 pages
|
|
setLoading(false)
|
|
}, 1000)
|
|
|
|
return () => clearTimeout(timer)
|
|
}, [document])
|
|
|
|
const handleDownload = () => {
|
|
if (document.previewUrl) {
|
|
const link = window.document.createElement('a')
|
|
link.href = document.previewUrl
|
|
link.download = document.name
|
|
link.click()
|
|
}
|
|
}
|
|
|
|
const isPDF = document.type.includes('pdf') || document.name.toLowerCase().endsWith('.pdf')
|
|
|
|
if (!isPDF) {
|
|
return (
|
|
<Paper sx={{ p: 3, mt: 2 }}>
|
|
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
<Typography variant="h6">{document.name}</Typography>
|
|
<IconButton onClick={onClose} title="Fermer">
|
|
<Close />
|
|
</IconButton>
|
|
</Box>
|
|
<Alert severity="info">
|
|
Aperçu non disponible pour ce type de fichier ({document.type})
|
|
</Alert>
|
|
</Paper>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Dialog open onClose={onClose} maxWidth="lg" fullWidth>
|
|
<DialogTitle>
|
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
|
<Box display="flex" alignItems="center" gap={1}>
|
|
<PictureAsPdf color="error" />
|
|
<Typography variant="h6">{document.name}</Typography>
|
|
</Box>
|
|
<IconButton onClick={onClose} title="Fermer">
|
|
<Close />
|
|
</IconButton>
|
|
</Box>
|
|
</DialogTitle>
|
|
|
|
<DialogContent dividers>
|
|
{loading && (
|
|
<Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
|
|
<CircularProgress />
|
|
<Typography variant="body2" sx={{ ml: 2 }}>
|
|
Chargement du PDF...
|
|
</Typography>
|
|
</Box>
|
|
)}
|
|
|
|
{error && (
|
|
<Alert severity="error" sx={{ mb: 2 }}>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
{!loading && !error && (
|
|
<Box>
|
|
{/* Contrôles de navigation */}
|
|
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
<Box display="flex" alignItems="center" gap={1}>
|
|
<Button
|
|
variant="outlined"
|
|
size="small"
|
|
startIcon={<NavigateBefore />}
|
|
onClick={() => setPage(prev => Math.max(prev - 1, 1))}
|
|
disabled={page <= 1}
|
|
>
|
|
Précédent
|
|
</Button>
|
|
<Typography variant="body2">
|
|
Page {page} sur {numPages}
|
|
</Typography>
|
|
<Button
|
|
variant="outlined"
|
|
size="small"
|
|
endIcon={<NavigateNext />}
|
|
onClick={() => setPage(prev => Math.min(prev + 1, numPages))}
|
|
disabled={page >= numPages}
|
|
>
|
|
Suivant
|
|
</Button>
|
|
</Box>
|
|
|
|
<Box display="flex" alignItems="center" gap={1}>
|
|
<Button
|
|
variant="outlined"
|
|
size="small"
|
|
startIcon={<ZoomOut />}
|
|
onClick={() => setScale(prev => Math.max(prev - 0.2, 0.5))}
|
|
>
|
|
Zoom -
|
|
</Button>
|
|
<Typography variant="body2">
|
|
{Math.round(scale * 100)}%
|
|
</Typography>
|
|
<Button
|
|
variant="outlined"
|
|
size="small"
|
|
startIcon={<ZoomIn />}
|
|
onClick={() => setScale(prev => Math.min(prev + 0.2, 2.0))}
|
|
>
|
|
Zoom +
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
{/* Aperçu PDF avec viewer intégré */}
|
|
<Box sx={{
|
|
border: '1px solid',
|
|
borderColor: 'grey.300',
|
|
borderRadius: 1,
|
|
overflow: 'hidden',
|
|
maxHeight: '70vh',
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
backgroundColor: 'grey.50'
|
|
}}>
|
|
{document.previewUrl ? (
|
|
<Box sx={{ width: '100%', height: '600px' }}>
|
|
{/* Utiliser un viewer PDF intégré */}
|
|
<iframe
|
|
src={`${document.previewUrl}#toolbar=1&navpanes=1&scrollbar=1&page=1&view=FitH`}
|
|
width="100%"
|
|
height="100%"
|
|
style={{
|
|
border: 'none',
|
|
transform: `scale(${scale})`,
|
|
transformOrigin: 'top left',
|
|
width: `${100 / scale}%`,
|
|
height: `${600 / scale}px`
|
|
}}
|
|
title={`Aperçu de ${document.name}`}
|
|
onLoad={() => setLoading(false)}
|
|
onError={() => {
|
|
setError('Erreur de chargement du PDF')
|
|
setLoading(false)
|
|
}}
|
|
/>
|
|
</Box>
|
|
) : (
|
|
<Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
|
|
<Box textAlign="center">
|
|
<PictureAsPdf sx={{ fontSize: 64, color: 'error.main', mb: 2 }} />
|
|
<Typography variant="h6" gutterBottom>
|
|
Aperçu PDF
|
|
</Typography>
|
|
<Typography variant="body2" color="text.secondary">
|
|
Le fichier PDF "{document.name}" a été uploadé avec succès.
|
|
</Typography>
|
|
<Typography variant="body2" color="text.secondary">
|
|
Taille: {(document.size / 1024 / 1024).toFixed(2)} MB
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
</DialogContent>
|
|
|
|
<DialogActions>
|
|
<Button onClick={onClose}>
|
|
Fermer
|
|
</Button>
|
|
<Button
|
|
variant="contained"
|
|
startIcon={<Download />}
|
|
onClick={handleDownload}
|
|
disabled={!document.previewUrl}
|
|
>
|
|
Télécharger
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
)
|
|
} |