import React, { useState, useCallback } from 'react'; import { InfoItem, AIProvider, ItemType, Priority, Status, SecurityLevel, ExtractedEntity } from '../types'; import { multiProviderAI } from '../services/multiProviderAI'; interface QuickCaptureProps { onCapture: (item: InfoItem) => void; onClose: () => void; aiProvider: AIProvider; theme: 'dark' | 'light'; } interface ParsedResult { title: string; content: string; type: ItemType; tags: string[]; priority: Priority; entities: ExtractedEntity[]; confidence: number; } export function QuickCapture({ onCapture, onClose, aiProvider, theme }: QuickCaptureProps) { const [rawInput, setRawInput] = useState(''); const [isProcessing, setIsProcessing] = useState(false); const [parsedResult, setParsedResult] = useState(null); const [editMode, setEditMode] = useState(false); // Editable fields const [title, setTitle] = useState(''); const [content, setContent] = useState(''); const [type, setType] = useState('note'); const [tags, setTags] = useState([]); const [priority, setPriority] = useState('medium'); const [securityLevel, setSecurityLevel] = useState('internal'); const [newTag, setNewTag] = useState(''); const cardClasses = theme === 'dark' ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200'; const inputClasses = theme === 'dark' ? 'bg-gray-700 border-gray-600' : 'bg-gray-50 border-gray-300'; // Parse raw input with AI const parseWithAI = useCallback(async () => { if (!rawInput.trim()) return; setIsProcessing(true); try { const result = await multiProviderAI.parseQuickCapture(rawInput, aiProvider); setParsedResult(result); setTitle(result.title); setContent(result.content || rawInput); setType(result.type); setTags(result.tags); setPriority(result.priority); setEditMode(true); } catch (error) { console.error('AI parsing failed:', error); // Fallback to basic parsing const lines = rawInput.split('\n'); setTitle(lines[0].substring(0, 100)); setContent(rawInput); setType('note'); setTags([]); setPriority('medium'); setEditMode(true); } finally { setIsProcessing(false); } }, [rawInput, aiProvider]); // Quick type detection based on content patterns const detectType = useCallback((text: string): ItemType => { const lowerText = text.toLowerCase(); if (lowerText.includes('@') && lowerText.includes('.')) return 'contact'; if (lowerText.includes('http://') || lowerText.includes('https://')) return 'link'; if (lowerText.includes('todo:') || lowerText.includes('task:') || lowerText.includes('[]')) return 'task'; if (lowerText.includes('idea:') || lowerText.includes('💡')) return 'idea'; if (lowerText.includes('project:') || lowerText.includes('projekt:')) return 'project'; if (lowerText.includes('person:') || lowerText.includes('navn:')) return 'person'; return 'note'; }, []); // Quick local parse (no AI) const quickParse = useCallback(() => { const lines = rawInput.split('\n').filter(l => l.trim()); const detectedType = detectType(rawInput); // Extract potential tags (words starting with #) const hashTags = rawInput.match(/#\w+/g)?.map(t => t.substring(1)) || []; // Extract URLs const urls = rawInput.match(/https?:\/\/[^\s]+/g) || []; // Extract emails const emails = rawInput.match(/[\w.-]+@[\w.-]+\.\w+/g) || []; setTitle(lines[0]?.substring(0, 100) || 'Ny note'); setContent(rawInput); setType(detectedType); setTags(hashTags); setPriority('medium'); setEditMode(true); setParsedResult({ title: lines[0] || 'Ny note', content: rawInput, type: detectedType, tags: hashTags, priority: 'medium', entities: [ ...urls.map(u => ({ type: 'url', value: u, confidence: 1 })), ...emails.map(e => ({ type: 'email', value: e, confidence: 1 })), ], confidence: 0.6, }); }, [rawInput, detectType]); // Add tag const addTag = () => { if (newTag.trim() && !tags.includes(newTag.trim())) { setTags([...tags, newTag.trim()]); setNewTag(''); } }; // Remove tag const removeTag = (tag: string) => { setTags(tags.filter(t => t !== tag)); }; // Submit the item const handleSubmit = () => { const item: InfoItem = { id: crypto.randomUUID(), type, title, content, tags, priority, status: 'active' as Status, securityLevel, createdAt: new Date(), updatedAt: new Date(), metadata: parsedResult ? { aiParsed: true, confidence: parsedResult.confidence, entities: parsedResult.entities, } : undefined, }; onCapture(item); }; // Paste handler const handlePaste = async (e: React.ClipboardEvent) => { const text = e.clipboardData.getData('text'); if (text.length > 50) { // Auto-parse on large paste setRawInput(text); setTimeout(quickParse, 100); } }; return (
{/* Header */}

Quick Capture

{aiProvider}
{/* Content */}
{!editMode ? ( <> {/* Raw input */}