4NK_IA_front/src/views/UploadView.tsx

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>
)
}