171 lines
5.2 KiB
TypeScript
171 lines
5.2 KiB
TypeScript
import { useCallback, useState } from 'react'
|
|
import { useDropzone } from 'react-dropzone'
|
|
import { Box, Typography, Paper, CircularProgress, Alert, Button, Chip, Grid } from '@mui/material'
|
|
import {
|
|
CloudUpload,
|
|
CheckCircle,
|
|
Error,
|
|
HourglassEmpty,
|
|
Visibility,
|
|
} from '@mui/icons-material'
|
|
import { useAppDispatch, useAppSelector } from '../store'
|
|
import { uploadDocument } from '../store/documentSlice'
|
|
import { Layout } from '../components/Layout'
|
|
import { FilePreview } from '../components/FilePreview'
|
|
import type { Document } from '../types'
|
|
|
|
export default function UploadView() {
|
|
const dispatch = useAppDispatch()
|
|
const { documents, error } = useAppSelector((state) => state.document)
|
|
const [previewDocument, setPreviewDocument] = useState<Document | null>(null)
|
|
|
|
const onDrop = useCallback(
|
|
(acceptedFiles: File[]) => {
|
|
acceptedFiles.forEach((file) => {
|
|
dispatch(uploadDocument(file))
|
|
})
|
|
},
|
|
[dispatch]
|
|
)
|
|
|
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
onDrop,
|
|
accept: {
|
|
'application/pdf': ['.pdf'],
|
|
'image/*': ['.png', '.jpg', '.jpeg', '.tiff'],
|
|
'text/plain': ['.txt'],
|
|
'text/markdown': ['.md'],
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
|
|
},
|
|
multiple: true,
|
|
})
|
|
|
|
const getStatusIcon = (status: string) => {
|
|
switch (status) {
|
|
case 'completed':
|
|
return <CheckCircle color="success" />
|
|
case 'error':
|
|
return <Error color="error" />
|
|
case 'processing':
|
|
return <CircularProgress size={20} />
|
|
default:
|
|
return <HourglassEmpty color="action" />
|
|
}
|
|
}
|
|
|
|
const getStatusColor = (status: string) => {
|
|
switch (status) {
|
|
case 'completed':
|
|
return 'success'
|
|
case 'error':
|
|
return 'error'
|
|
case 'processing':
|
|
return 'warning'
|
|
default:
|
|
return 'default'
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Layout>
|
|
<Typography variant="h4" gutterBottom>
|
|
Téléversement de documents
|
|
</Typography>
|
|
|
|
<Paper
|
|
{...getRootProps()}
|
|
sx={{
|
|
p: 4,
|
|
textAlign: 'center',
|
|
cursor: 'pointer',
|
|
border: '2px dashed',
|
|
borderColor: isDragActive ? 'primary.main' : 'grey.300',
|
|
bgcolor: isDragActive ? 'action.hover' : 'background.paper',
|
|
'&:hover': {
|
|
borderColor: 'primary.main',
|
|
bgcolor: 'action.hover',
|
|
},
|
|
}}
|
|
>
|
|
<input {...getInputProps()} />
|
|
<CloudUpload sx={{ fontSize: 48, color: 'primary.main', mb: 2 }} />
|
|
<Typography variant="h6" gutterBottom>
|
|
{isDragActive
|
|
? 'Déposez les fichiers ici...'
|
|
: 'Glissez-déposez vos documents ou cliquez pour sélectionner'}
|
|
</Typography>
|
|
<Typography variant="body2" color="text.secondary">
|
|
Formats acceptés: PDF, PNG, JPG, JPEG, TIFF, TXT, MD, DOCX
|
|
</Typography>
|
|
</Paper>
|
|
|
|
{error && (
|
|
<Alert severity="error" sx={{ mt: 2 }}>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
{documents.length > 0 && (
|
|
<Box sx={{ mt: 3 }}>
|
|
<Typography variant="h6" gutterBottom>
|
|
Documents téléversés ({documents.length})
|
|
</Typography>
|
|
|
|
<Grid container spacing={2}>
|
|
{documents.map((doc, index) => (
|
|
<Grid size={{ xs: 12, md: 6 }} key={`${doc.id}-${index}`}>
|
|
<Paper sx={{ p: 2 }}>
|
|
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
|
<Box display="flex" alignItems="center" gap={1}>
|
|
{getStatusIcon(doc.status)}
|
|
<Typography variant="subtitle1" noWrap>
|
|
{doc.name}
|
|
</Typography>
|
|
</Box>
|
|
<Box display="flex" gap={1}>
|
|
<Button
|
|
size="small"
|
|
startIcon={<Visibility />}
|
|
onClick={() => setPreviewDocument(doc)}
|
|
disabled={doc.status !== 'completed'}
|
|
>
|
|
Aperçu
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Box display="flex" gap={1} flexWrap="wrap">
|
|
<Chip
|
|
label={doc.functionalType || doc.mimeType}
|
|
size="small"
|
|
variant="outlined"
|
|
/>
|
|
<Chip
|
|
label={doc.status}
|
|
size="small"
|
|
color={getStatusColor(doc.status) as 'success' | 'error' | 'warning' | 'default'}
|
|
/>
|
|
<Chip
|
|
label={`${(doc.size / 1024 / 1024).toFixed(2)} MB`}
|
|
size="small"
|
|
variant="outlined"
|
|
/>
|
|
</Box>
|
|
</Paper>
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Aperçu du document */}
|
|
{previewDocument && (
|
|
<FilePreview
|
|
document={previewDocument}
|
|
onClose={() => setPreviewDocument(null)}
|
|
/>
|
|
)}
|
|
</Layout>
|
|
)
|
|
}
|