'use client'; import { Suspense, useState, useEffect } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { NoteEditor } from '@/components/NoteEditor'; import { FileUpload } from '@/components/FileUpload'; import { VoiceRecorder } from '@/components/VoiceRecorder'; import { Header } from '@/components/Header'; import { authFetch } from '@/lib/authFetch'; const NOTE_TYPES = [ { value: 'NOTE', label: 'Note', desc: 'Rich text note' }, { value: 'CLIP', label: 'Clip', desc: 'Web clipping' }, { value: 'BOOKMARK', label: 'Bookmark', desc: 'Save a URL' }, { value: 'CODE', label: 'Code', desc: 'Code snippet' }, { value: 'IMAGE', label: 'Image', desc: 'Upload image' }, { value: 'FILE', label: 'File', desc: 'Upload file' }, { value: 'AUDIO', label: 'Audio', desc: 'Voice recording' }, ]; interface NotebookOption { id: string; title: string; } export default function NewNotePage() { return ( }> ); } function NewNoteForm() { const router = useRouter(); const searchParams = useSearchParams(); const preselectedNotebook = searchParams.get('notebookId'); const [title, setTitle] = useState(''); const [content, setContent] = useState(''); const [type, setType] = useState('NOTE'); const [url, setUrl] = useState(''); const [language, setLanguage] = useState(''); const [tags, setTags] = useState(''); const [fileUrl, setFileUrl] = useState(''); const [mimeType, setMimeType] = useState(''); const [fileSize, setFileSize] = useState(0); const [duration, setDuration] = useState(0); const [notebookId, setNotebookId] = useState(preselectedNotebook || ''); const [notebooks, setNotebooks] = useState([]); const [saving, setSaving] = useState(false); useEffect(() => { fetch('/api/notebooks') .then((res) => res.json()) .then((data) => setNotebooks(data.map((nb: NotebookOption) => ({ id: nb.id, title: nb.title })))) .catch(console.error); }, []); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!title.trim() || saving) return; setSaving(true); try { const body: Record = { title, content, type, tags: tags.split(',').map((t) => t.trim()).filter(Boolean), }; if (notebookId) body.notebookId = notebookId; if (url) body.url = url; if (language) body.language = language; if (fileUrl) body.fileUrl = fileUrl; if (mimeType) body.mimeType = mimeType; if (fileSize) body.fileSize = fileSize; if (duration) body.duration = duration; const endpoint = notebookId ? `/api/notebooks/${notebookId}/notes` : '/api/notes'; const res = await authFetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); const note = await res.json(); if (res.ok) { router.push(`/notes/${note.id}`); } } catch (error) { console.error('Failed to create note:', error); } finally { setSaving(false); } }; const showUrl = ['CLIP', 'BOOKMARK'].includes(type); const showUpload = ['IMAGE', 'FILE'].includes(type); const showLanguage = type === 'CODE'; const showRecorder = type === 'AUDIO'; return ( Create Note {/* Type selector */} Type {NOTE_TYPES.map((t) => ( setType(t.value)} className={`px-3 py-2 text-sm rounded-lg border transition-colors ${ type === t.value ? 'bg-amber-500/20 text-amber-400 border-amber-500/30' : 'bg-slate-800/50 text-slate-400 border-slate-700 hover:text-white hover:border-slate-600' }`} > {t.label} ))} {/* Title */} Title setTitle(e.target.value)} placeholder="Note title" className="w-full px-4 py-3 bg-slate-800/50 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:border-amber-500/50" autoFocus /> {/* URL field */} {showUrl && ( URL setUrl(e.target.value)} placeholder="https://..." className="w-full px-4 py-3 bg-slate-800/50 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:border-amber-500/50" /> )} {/* File upload */} {showUpload && ( {type === 'IMAGE' ? 'Upload Image' : 'Upload File'} {fileUrl ? ( {type === 'IMAGE' && ( )} {fileUrl.split('/').pop()} {mimeType} · {(fileSize / 1024).toFixed(1)} KB { setFileUrl(''); setMimeType(''); setFileSize(0); }} className="text-slate-400 hover:text-red-400 text-sm" > Remove ) : ( { setFileUrl(result.url); setMimeType(result.mimeType); setFileSize(result.size); if (!title) setTitle(result.originalName); }} /> )} Or paste a URL setUrl(e.target.value)} placeholder="https://..." className="w-full px-3 py-2 bg-slate-800/50 border border-slate-700 rounded-lg text-white text-sm placeholder-slate-500 focus:outline-none focus:border-amber-500/50" /> )} {/* Language field */} {showLanguage && ( Language setLanguage(e.target.value)} placeholder="typescript, python, rust..." className="w-full px-4 py-3 bg-slate-800/50 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:border-amber-500/50" /> )} {/* Voice recorder */} {showRecorder && ( Recording { setFileUrl(result.fileUrl); setMimeType(result.mimeType); setFileSize(result.fileSize); setDuration(result.duration); setContent(result.transcript); if (!title) setTitle(`Voice note ${new Date().toLocaleDateString()}`); }} /> {content && ( Transcript {content} )} )} {/* Content */} {!showRecorder && ( Content )} {/* Notebook */} Notebook (optional) setNotebookId(e.target.value)} className="w-full px-4 py-3 bg-slate-800/50 border border-slate-700 rounded-lg text-white focus:outline-none focus:border-amber-500/50" > No notebook (standalone) {notebooks.map((nb) => ( {nb.title} ))} {/* Tags */} Tags (comma-separated) setTags(e.target.value)} placeholder="research, web3, draft" className="w-full px-4 py-3 bg-slate-800/50 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:border-amber-500/50" /> {/* Submit */} {saving ? 'Creating...' : 'Create Note'} router.back()} className="px-6 py-3 border border-slate-700 hover:border-slate-600 text-white rounded-lg transition-colors" > Cancel ); }
{fileUrl.split('/').pop()}
{mimeType} · {(fileSize / 1024).toFixed(1)} KB