import { useState, useRef, useCallback } from 'react' import { Code2, ImageIcon, Upload } from 'lucide-react' import { Modal } from '@/components/common/Modal' import { Button } from '@/components/ui/Button' import { cn } from '@/lib/utils' import { createSupportingData } from '@/api/supportingData' import { toast } from '@/lib/toast' interface AddSupportingDataModalProps { isOpen: boolean onClose: () => void sessionId: string onAdded: () => void } type TabType = 'text_snippet' | 'screenshot' const MAX_FILE_SIZE = 2 * 1024 * 1024 // 2MB export function AddSupportingDataModal({ isOpen, onClose, sessionId, onAdded }: AddSupportingDataModalProps) { const [activeTab, setActiveTab] = useState('text_snippet') const [label, setLabel] = useState('') const [textContent, setTextContent] = useState('') const [imageBase64, setImageBase64] = useState(null) const [imageContentType, setImageContentType] = useState(null) const [imageFileName, setImageFileName] = useState(null) const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState(null) const fileInputRef = useRef(null) const resetForm = () => { setLabel('') setTextContent('') setImageBase64(null) setImageContentType(null) setImageFileName(null) setError(null) setActiveTab('text_snippet') } const handleClose = () => { resetForm() onClose() } const processFile = useCallback((file: File) => { if (file.size > MAX_FILE_SIZE) { setError('File must be under 2MB') return } if (!['image/png', 'image/jpeg', 'image/svg+xml'].includes(file.type)) { setError('Only PNG, JPEG, and SVG files are supported') return } setError(null) setImageFileName(file.name) setImageContentType(file.type) const reader = new FileReader() reader.onload = () => { const result = reader.result as string // Strip the data:... prefix to get raw base64 const base64 = result.includes(',') ? result.split(',')[1] : result setImageBase64(base64) } reader.readAsDataURL(file) }, []) const handleFileChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) processFile(file) } const handlePaste = useCallback((e: React.ClipboardEvent) => { const items = e.clipboardData?.items if (!items) return for (const item of items) { if (item.type.startsWith('image/')) { e.preventDefault() const file = item.getAsFile() if (file) processFile(file) return } } }, [processFile]) const handleSubmit = async () => { if (!label.trim()) { setError('Label is required') return } if (activeTab === 'text_snippet' && !textContent.trim()) { setError('Content is required') return } if (activeTab === 'screenshot' && !imageBase64) { setError('Please select or paste an image') return } setIsSubmitting(true) setError(null) try { await createSupportingData(sessionId, { label: label.trim(), data_type: activeTab, content: activeTab === 'text_snippet' ? textContent : imageBase64!, content_type: activeTab === 'screenshot' ? (imageContentType ?? undefined) : undefined, }) toast.success('Supporting data added') onAdded() handleClose() } catch (err) { console.error('Failed to add supporting data:', err) setError('Failed to save. Please try again.') } finally { setIsSubmitting(false) } } return ( {/* Tabs */}
{/* Label */}
setLabel(e.target.value)} placeholder={activeTab === 'text_snippet' ? 'e.g. Error log output' : 'e.g. Blue screen photo'} className={cn( 'w-full rounded-md border border-border bg-card px-3 py-2 text-sm', 'text-foreground placeholder:text-muted-foreground', 'focus:border-[rgba(249,115,22,0.3)] focus:outline-hidden focus:ring-1 focus:ring-primary/20' )} />
{/* Text Snippet Tab Content */} {activeTab === 'text_snippet' && (