function AdvancedNotes({ user, token, actionParams, setActionParams }) { const [view, setView] = useState('list'); const [notes, setNotes] = useState([]); const [currentNote, setCurrentNote] = useState(null); const [loading, setLoading] = useState(false); const [metadata, setMetadata] = useState({ tags: [], subjects: [], groups: [] }); const [settings, setSettings] = useState({ store_original_files: true }); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editingNote, setEditingNote] = useState(null); const [newNoteData, setNewNoteData] = useState({ title: '', subject: '', tags: [], note_group: '', canvas_enabled: false }); const [showSubjectInput, setShowSubjectInput] = useState(false); const [showGroupInput, setShowGroupInput] = useState(false); const [newSubjectInput, setNewSubjectInput] = useState(''); const [newGroupInput, setNewGroupInput] = useState(''); const [openNoteId, setOpenNoteId] = useState(null); const [viewMode, setViewMode] = useState('list'); // 'list' or 'canvas' const [activeFilters, setActiveFilters] = useState({ subject: null, group: null, timeline: null }); const [showFilters, setShowFilters] = useState(false); useEffect(() => { loadNotes(); loadMetadata(); loadSettings(); }, [activeFilters]); useEffect(() => { if (actionParams?.action === 'create') { setShowCreateModal(true); if (setActionParams) setActionParams(null); } }, [actionParams]); const loadNotes = async () => { try { // Build query string from active filters const params = new URLSearchParams(); if (activeFilters.subject) params.append('subject', activeFilters.subject); if (activeFilters.group) params.append('group', activeFilters.group); if (activeFilters.timeline) params.append('date_filter', activeFilters.timeline); const queryString = params.toString(); const url = `${API_URL}/notes${queryString ? '?' + queryString : ''}`; const response = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); setNotes(data.notes || []); } catch (err) { console.error('Failed to load notes:', err); } }; const loadMetadata = async () => { try { const [tags, subjects, groups] = await Promise.all([ fetch(`${API_URL}/metadata/tags`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()), fetch(`${API_URL}/metadata/subjects`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()), fetch(`${API_URL}/metadata/groups`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()) ]); setMetadata({ tags: tags.tags || [], subjects: subjects.subjects || [], groups: groups.groups || [] }); } catch (err) { console.error('Failed to load metadata:', err); } }; const loadSettings = async () => { try { const response = await fetch(`${API_URL}/settings`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); setSettings(data); } catch (err) { console.error('Failed to load settings:', err); } }; const createNote = async () => { if (!newNoteData.subject && newNoteData.tags.length === 0 && !newNoteData.note_group) { alert('Please provide at least one of: Subject, Tag, or Group'); return; } try { setLoading(true); const response = await fetch(`${API_URL}/notes/create`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify(newNoteData) }); const data = await response.json(); if (!response.ok) throw new Error(data.detail); await loadNotes(); setShowCreateModal(false); setNewNoteData({ title: '', subject: '', tags: [], note_group: '', canvas_enabled: false }); openNote(data.note_id); } catch (err) { alert(`Failed to create note: ${err.message}`); } finally { setLoading(false); } }; const openNote = async (noteId) => { try { const response = await fetch(`${API_URL}/notes/${noteId}`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); setCurrentNote(data); setView('canvas'); } catch (err) { alert('Failed to load note'); } }; const deleteNote = async (noteId) => { if (!confirm('Are you sure you want to delete this note?')) return; try { await fetch(`${API_URL}/notes/${noteId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); await loadNotes(); } catch (err) { alert('Failed to delete note'); } }; const extractNote = async (noteId) => { try { await fetch(`${API_URL}/notes/${noteId}/extract`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ extract_now: true }) }); alert('Extraction started!'); await loadNotes(); } catch (err) { alert('Failed to extract note'); } }; const editMetadata = (note) => { setEditingNote({ ...note, subject: note.subject || '', note_group: note.note_group || '' }); setShowEditModal(true); }; const changeSubject = async (note) => { const newSubject = prompt(`Change subject for "${note.title}"\nCurrent: ${note.subject || 'None'}\n\nEnter new subject:`, note.subject || ''); if (newSubject !== null && newSubject.trim() !== note.subject) { try { const response = await fetch(`${API_URL}/notes/${note.id}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ subject: newSubject.trim() || null }) }); if (response.ok) { await loadNotes(); // Refresh to show updated subject } else { alert('Failed to update subject'); } } catch (err) { alert('Failed to update subject'); } } }; const changeGroup = async (note) => { const newGroup = prompt(`Change group for "${note.title}"\nCurrent: ${note.note_group || 'None'}\n\nEnter new group:`, note.note_group || ''); if (newGroup !== null && newGroup.trim() !== note.note_group) { try { const response = await fetch(`${API_URL}/notes/${note.id}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ note_group: newGroup.trim() || null }) }); if (response.ok) { await loadNotes(); // Refresh to show updated group } else { alert('Failed to update group'); } } catch (err) { alert('Failed to update group'); } } }; const archiveNote = async (noteId) => { if (!confirm('Archive this note?')) return; try { const response = await fetch(`${API_URL}/notes/${noteId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ archived: true }) }); if (response.ok) { await loadNotes(); } else { alert('Failed to archive note'); } } catch (err) { alert('Failed to archive note'); } }; const groupNotesByDate = (notes) => { const today = new Date(); const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); const grouped = { today: [], yesterday: [], older: [] }; notes.forEach(note => { const noteDate = new Date(note.created_at); if (noteDate.toDateString() === today.toDateString()) { grouped.today.push(note); } else if (noteDate.toDateString() === yesterday.toDateString()) { grouped.yesterday.push(note); } else { grouped.older.push(note); } }); return grouped; }; if (view === 'canvas' && currentNote) { return { setView('list'); setCurrentNote(null); loadNotes(); }} />; } const groupedNotes = groupNotesByDate(notes); return (

📝 My Notes

{/* Filter Component */} {showFilters && ( setActiveFilters(filters)} /> )} {showCreateModal && (
setShowCreateModal(false)}>
e.stopPropagation()}>

Create New Note

setNewNoteData({ ...newNoteData, title: e.target.value })} placeholder="Enter note title" />
{showSubjectInput ? (
setNewSubjectInput(e.target.value)} placeholder="Enter new subject name" autoFocus />
) : ( )}
{showGroupInput ? (
setNewGroupInput(e.target.value)} placeholder="Enter new group name" autoFocus />
) : ( )}

* At least one of Subject, Tag, or Group is required

)} {groupedNotes.today.length > 0 && (

📅 TODAY

{groupedNotes.today.map(note => openNote(note.id)} onDelete={() => deleteNote(note.id)} onExtract={() => extractNote(note.id)} onChangeSubject={() => changeSubject(note)} onChangeGroup={() => changeGroup(note)} onArchive={() => archiveNote(note.id)} />)}
)} {groupedNotes.yesterday.length > 0 && (

📅 YESTERDAY

{groupedNotes.yesterday.map(note => openNote(note.id)} onDelete={() => deleteNote(note.id)} onExtract={() => extractNote(note.id)} onChangeSubject={() => changeSubject(note)} onChangeGroup={() => changeGroup(note)} onArchive={() => archiveNote(note.id)} />)}
)} {groupedNotes.older.length > 0 && (

📅 OLDER

{groupedNotes.older.map(note => openNote(note.id)} onDelete={() => deleteNote(note.id)} onExtract={() => extractNote(note.id)} onChangeSubject={() => changeSubject(note)} onChangeGroup={() => changeGroup(note)} onArchive={() => archiveNote(note.id)} />)}
)} {notes.length === 0 && (

No notes yet

Click "New Note" to create your first note

)}
); } // Export to global scope window.AdvancedNotes = AdvancedNotes;