import { useState } from 'react'; import { Check, X, Send, MessageSquare, HelpCircle } from 'lucide-react'; import { FETAL_VIEW_LABELS, submitFeedback, FeedbackCreate, ClassificationResult } from '../lib/api'; interface FeedbackSectionProps { sessionId: string; filename: string; fileType: 'dicom' | 'image'; predictions: ClassificationResult[]; topPrediction: ClassificationResult | null; patientId?: string; imageHash?: string; preprocessedImageBase64?: string; onFeedbackSubmitted?: () => void; onViewCorrected?: (correctedLabel: string) => void; disabled?: boolean; } export function FeedbackSection({ sessionId, filename, fileType, predictions, topPrediction, patientId, imageHash, preprocessedImageBase64, onFeedbackSubmitted, onViewCorrected, disabled = false, }: FeedbackSectionProps) { const [feedbackState, setFeedbackState] = useState<'none' | 'correct' | 'incorrect' | 'not_sure'>('none'); const [correctLabel, setCorrectLabel] = useState(''); const [notes, setNotes] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const [submitted, setSubmitted] = useState(false); const handleFeedback = async (isCorrect: boolean | null) => { if (disabled || !topPrediction) return; if (isCorrect === true) { // Submit immediately for correct predictions setFeedbackState('correct'); await submitFeedbackData(true); } else if (isCorrect === null) { // Show notes form for uncertain predictions setFeedbackState('not_sure'); } else { // Show correction form for incorrect predictions setFeedbackState('incorrect'); } }; const submitFeedbackData = async (isCorrect: boolean | null, overrideLabel?: string, overrideNotes?: string) => { if (!topPrediction || isSubmitting) return; setIsSubmitting(true); try { const feedbackData: FeedbackCreate = { session_id: sessionId, filename, file_type: fileType, predicted_label: topPrediction.label, predicted_confidence: topPrediction.confidence, all_predictions: predictions.map(p => ({ label: p.label, probability: p.confidence })), is_correct: isCorrect, correct_label: overrideLabel || correctLabel || undefined, reviewer_notes: overrideNotes || notes || undefined, patient_id: patientId, image_hash: imageHash, preprocessed_image_base64: preprocessedImageBase64, }; await submitFeedback(feedbackData); setSubmitted(true); onFeedbackSubmitted?.(); } catch (error) { console.error('Failed to submit feedback:', error); } finally { setIsSubmitting(false); } }; const handleSubmitCorrection = async () => { if (!correctLabel) return; await submitFeedbackData(false, correctLabel, notes); onViewCorrected?.(correctLabel); }; const handleSubmitNotSure = async () => { await submitFeedbackData(null, undefined, notes); }; if (submitted) { return (
Feedback recorded {feedbackState === 'correct' ? ( Confirmed correct ) : feedbackState === 'not_sure' ? ( Marked as uncertain ) : ( Corrected to: {correctLabel} )}
); } if (disabled || !topPrediction) { return (
Run classification to provide feedback
); } return (
{/* Feedback header */}
Is this prediction correct?
{feedbackState === 'none' && (
)}
{/* Correction form */} {feedbackState === 'incorrect' && (
{/* Native select - handles viewport boundaries automatically */}
{/* Notes input */}