ux(review): spinner, tooltip, chip en cours et snackbar sur Révision IA
This commit is contained in:
parent
4bed3562b1
commit
1e207f734e
@ -8,6 +8,8 @@ import {
|
|||||||
Skeleton,
|
Skeleton,
|
||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
|
Snackbar,
|
||||||
|
Alert as MuiAlert,
|
||||||
Chip,
|
Chip,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
@ -50,7 +52,7 @@ import type { Document } from '../types'
|
|||||||
import { confirmDetectedAddress, deleteFolderFile, reviewFileWithAI } from '../services/folderApi'
|
import { confirmDetectedAddress, deleteFolderFile, reviewFileWithAI } from '../services/folderApi'
|
||||||
|
|
||||||
// Composant mémorisé pour les items de la liste
|
// Composant mémorisé pour les items de la liste
|
||||||
const DocumentListItem = memo(({ doc, index, onPreview, onDelete, onReplace, onConfirmAddress, onReview, onOpenCorrections, totalCount }: {
|
const DocumentListItem = memo(({ doc, index, onPreview, onDelete, onReplace, onConfirmAddress, onReview, onOpenCorrections, isReviewing, totalCount }: {
|
||||||
doc: Document,
|
doc: Document,
|
||||||
index: number,
|
index: number,
|
||||||
onPreview: (doc: Document) => void,
|
onPreview: (doc: Document) => void,
|
||||||
@ -59,6 +61,7 @@ const DocumentListItem = memo(({ doc, index, onPreview, onDelete, onReplace, onC
|
|||||||
onConfirmAddress: (doc: Document) => void,
|
onConfirmAddress: (doc: Document) => void,
|
||||||
onReview: (doc: Document) => void,
|
onReview: (doc: Document) => void,
|
||||||
onOpenCorrections: (doc: Document, corrections: any[]) => void,
|
onOpenCorrections: (doc: Document, corrections: any[]) => void,
|
||||||
|
isReviewing: boolean,
|
||||||
totalCount: number
|
totalCount: number
|
||||||
}) => {
|
}) => {
|
||||||
const getFileIcon = (mimeType: string) => {
|
const getFileIcon = (mimeType: string) => {
|
||||||
@ -151,6 +154,9 @@ const DocumentListItem = memo(({ doc, index, onPreview, onDelete, onReplace, onC
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{isReviewing && (
|
||||||
|
<Chip color="default" label="Révision IA en cours…" size="small" />
|
||||||
|
)}
|
||||||
{(() => {
|
{(() => {
|
||||||
const anyDoc: any = doc as any
|
const anyDoc: any = doc as any
|
||||||
const score: number | undefined =
|
const score: number | undefined =
|
||||||
@ -223,14 +229,18 @@ const DocumentListItem = memo(({ doc, index, onPreview, onDelete, onReplace, onC
|
|||||||
>
|
>
|
||||||
Aperçu
|
Aperçu
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Tooltip title="Analyse IA (Ollama): calcule un score de fiabilité, propose des corrections, ajoute un avis.">
|
||||||
size="small"
|
<span>
|
||||||
onClick={() => onReview(doc)}
|
<Button
|
||||||
disabled={doc.status !== 'completed'}
|
size="small"
|
||||||
fullWidth
|
onClick={() => onReview(doc)}
|
||||||
>
|
disabled={doc.status !== 'completed' || isReviewing}
|
||||||
Révision IA
|
fullWidth
|
||||||
</Button>
|
>
|
||||||
|
{isReviewing ? 'Révision IA…' : 'Révision IA'}
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
color="error"
|
color="error"
|
||||||
@ -276,6 +286,8 @@ export default function UploadView() {
|
|||||||
const [reviewDialogOpen, setReviewDialogOpen] = useState(false)
|
const [reviewDialogOpen, setReviewDialogOpen] = useState(false)
|
||||||
const [reviewDoc, setReviewDoc] = useState<Document | null>(null)
|
const [reviewDoc, setReviewDoc] = useState<Document | null>(null)
|
||||||
const [reviewCorrections, setReviewCorrections] = useState<any[]>([])
|
const [reviewCorrections, setReviewCorrections] = useState<any[]>([])
|
||||||
|
const [reviewingId, setReviewingId] = useState<string | null>(null)
|
||||||
|
const [snack, setSnack] = useState<{ open: boolean; severity: 'success' | 'error'; message: string }>({ open: false, severity: 'success', message: '' })
|
||||||
|
|
||||||
const handleConfirmAddress = useCallback((doc: Document) => {
|
const handleConfirmAddress = useCallback((doc: Document) => {
|
||||||
try {
|
try {
|
||||||
@ -308,10 +320,15 @@ export default function UploadView() {
|
|||||||
const handleReview = useCallback(async (doc: Document) => {
|
const handleReview = useCallback(async (doc: Document) => {
|
||||||
if (!currentFolderHash) return
|
if (!currentFolderHash) return
|
||||||
try {
|
try {
|
||||||
|
setReviewingId(doc.id)
|
||||||
await reviewFileWithAI(currentFolderHash, doc.id)
|
await reviewFileWithAI(currentFolderHash, doc.id)
|
||||||
await dispatch(loadFolderResults(currentFolderHash)).unwrap()
|
await dispatch(loadFolderResults(currentFolderHash)).unwrap()
|
||||||
|
setSnack({ open: true, severity: 'success', message: 'Révision IA terminée: score et corrections mis à jour.' })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('❌ Révision IA:', e)
|
console.error('❌ Révision IA:', e)
|
||||||
|
setSnack({ open: true, severity: 'error', message: "Échec de la révision IA. Réessaie plus tard." })
|
||||||
|
} finally {
|
||||||
|
setReviewingId(null)
|
||||||
}
|
}
|
||||||
}, [currentFolderHash, dispatch])
|
}, [currentFolderHash, dispatch])
|
||||||
|
|
||||||
@ -581,6 +598,7 @@ export default function UploadView() {
|
|||||||
onConfirmAddress={handleConfirmAddress}
|
onConfirmAddress={handleConfirmAddress}
|
||||||
onReview={handleReview}
|
onReview={handleReview}
|
||||||
onOpenCorrections={(d, corr) => { setReviewDoc(d); setReviewCorrections(corr); setReviewDialogOpen(true) }}
|
onOpenCorrections={(d, corr) => { setReviewDoc(d); setReviewCorrections(corr); setReviewDialogOpen(true) }}
|
||||||
|
isReviewing={reviewingId === doc.id}
|
||||||
totalCount={memoizedDocuments.length}
|
totalCount={memoizedDocuments.length}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@ -780,6 +798,18 @@ export default function UploadView() {
|
|||||||
<Button onClick={() => setReviewDialogOpen(false)}>Fermer</Button>
|
<Button onClick={() => setReviewDialogOpen(false)}>Fermer</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Snackbar feedback */}
|
||||||
|
<Snackbar
|
||||||
|
open={snack.open}
|
||||||
|
autoHideDuration={3000}
|
||||||
|
onClose={() => setSnack({ ...snack, open: false })}
|
||||||
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||||
|
>
|
||||||
|
<MuiAlert onClose={() => setSnack({ ...snack, open: false })} severity={snack.severity} variant="filled" sx={{ width: '100%' }}>
|
||||||
|
{snack.message}
|
||||||
|
</MuiAlert>
|
||||||
|
</Snackbar>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user