'use client' import { useState, useEffect, useCallback } from 'react' import { Plus, X, Trash2, ShoppingCart, FileText, Check, Circle, Calendar as CalendarIcon } from 'lucide-react' interface NoteItem { id: string text: string done: boolean } interface Note { id: string type: 'note' | 'shopping' title: string items?: NoteItem[] text?: string color: string pinDate: string | null createdAt: string updatedAt: string } const NOTE_COLORS = ['#6366f1', '#ec4899', '#10b981', '#f59e0b', '#3b82f6', '#8b5cf6'] export default function NotesTab() { const [notes, setNotes] = useState([]) const [loading, setLoading] = useState(true) const [activeNote, setActiveNote] = useState(null) const [showCreate, setShowCreate] = useState(false) const [newItemText, setNewItemText] = useState('') const load = useCallback(async () => { try { const r = await fetch('/api/notes') const d = await r.json() setNotes(d.notes || []) } catch {} finally { setLoading(false) } }, []) useEffect(() => { load() }, [load]) const createNote = async (type: 'note' | 'shopping') => { const title = type === 'shopping' ? 'Список покупок' : 'Новая заметка' const color = NOTE_COLORS[notes.length % NOTE_COLORS.length] try { const r = await fetch('/api/notes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type, title, color }), }) const d = await r.json() setNotes(prev => [d.note, ...prev]) setActiveNote(d.note) setShowCreate(false) } catch {} } const updateNote = async (id: string, updates: Partial) => { try { const r = await fetch('/api/notes', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id, ...updates }), }) const d = await r.json() setNotes(prev => prev.map(n => n.id === id ? d.note : n)) if (activeNote?.id === id) setActiveNote(d.note) } catch {} } const deleteNote = async (id: string) => { try { await fetch(`/api/notes?id=${id}`, { method: 'DELETE' }) setNotes(prev => prev.filter(n => n.id !== id)) if (activeNote?.id === id) setActiveNote(null) } catch {} } const addItem = async () => { if (!newItemText.trim() || !activeNote) return const items = [...(activeNote.items || []), { id: Date.now().toString(36), text: newItemText.trim(), done: false }] await updateNote(activeNote.id, { items }) setNewItemText('') } const toggleItem = async (itemId: string) => { if (!activeNote) return const items = (activeNote.items || []).map(i => i.id === itemId ? { ...i, done: !i.done } : i) await updateNote(activeNote.id, { items }) } const removeItem = async (itemId: string) => { if (!activeNote) return const items = (activeNote.items || []).filter(i => i.id !== itemId) await updateNote(activeNote.id, { items }) } return (
{/* Left: notes list */}

Заметки

{/* Create new */} {showCreate && (
)} {/* Notes list */} {notes.map(note => { const isActive = activeNote?.id === note.id const doneCount = note.items?.filter(i => i.done).length || 0 const totalCount = note.items?.length || 0 return ( ) })} {!loading && notes.length === 0 && (
Нет заметок
Нажмите + чтобы создать
)}
{/* Right: note editor */}
{!activeNote ? (
Выберите заметку
) : ( <> {/* Header */}
{ const newTitle = e.target.value setActiveNote(prev => prev ? { ...prev, title: newTitle } : null) }} onBlur={() => updateNote(activeNote.id, { title: activeNote.title })} style={{ background: 'transparent', border: 'none', outline: 'none', fontSize: 18, fontWeight: 700, color: 'var(--text-primary)', fontFamily: 'inherit', flex: 1, minWidth: 0, }} />
{ const v = e.target.value || null setActiveNote(prev => prev ? { ...prev, pinDate: v } : null) updateNote(activeNote.id, { pinDate: v }) }} style={{ background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.07)', borderRadius: 10, padding: '6px 10px', color: 'var(--text-primary)', fontSize: 13, outline: 'none', fontFamily: 'inherit', colorScheme: 'dark' as any, }} /> {activeNote.pinDate && ( )}
{/* Content */}
{activeNote.type === 'shopping' ? ( <> {/* Add item */}
setNewItemText(e.target.value)} onKeyDown={e => e.key === 'Enter' && addItem()} placeholder="Добавить..." style={{ flex: 1, padding: '12px 16px', borderRadius: 12, background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.07)', color: 'var(--text-primary)', fontSize: 15, outline: 'none', fontFamily: 'inherit', boxSizing: 'border-box' as any, }} />
{/* Items */}
{(activeNote.items || []).filter(i => !i.done).map(item => (
))} {/* Done items */} {(activeNote.items || []).filter(i => i.done).length > 0 && ( <>
Выполнено
{(activeNote.items || []).filter(i => i.done).map(item => (
{item.text}
))} )}
) : ( /* Text note */