"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { ChevronDown, Copy, Download, ExternalLink, FileText, MessageSquareText, RefreshCcw, Trash2, X } from "lucide-react"; import { deleteNote, listNotes, type SavedNote } from "@/lib/student-activity"; import { useStudentActivityVersion } from "@/hooks/useStudentActivity"; import { buildStudyIntentUrl } from "@/lib/study-intents"; // ============================================================================= // Real saved notes — every entry here was saved by the student (from a // StudyChat answer, a notes-generation handoff, or the tuition demo). No // placeholder rows: the empty state points at the actions that create notes. // Extracted from the standalone /notes route so /library can compose it as a // tab; the /notes route is now a thin wrapper around this view. // ============================================================================= const SOURCE_LABEL: Record = { "study-chat": "StudyChat", "learn-anything": "Learn Anything", "tuition-demo": "Tuition demo", }; export function NotesView() { const [notes, setNotes] = useState([]); const [copiedId, setCopiedId] = useState(null); const [subjectFilter, setSubjectFilter] = useState(""); const [topicFilter, setTopicFilter] = useState(""); const [sourceFilter, setSourceFilter] = useState(""); const [openNote, setOpenNote] = useState(null); const activityVersion = useStudentActivityVersion(); useEffect(() => { // localStorage read on mount + whenever notes change (this tab or another). let cancelled = false; void Promise.resolve().then(() => { if (!cancelled) setNotes(listNotes()); }); return () => { cancelled = true; }; }, [activityVersion]); function handleCopy(note: SavedNote) { void navigator.clipboard?.writeText(`${note.title}\n\n${note.content}`).then(() => { setCopiedId(note.id); setTimeout(() => setCopiedId(null), 1500); }); } function handleDelete(id: string) { deleteNote(id); setNotes(listNotes()); if (openNote?.id === id) setOpenNote(null); } function handleExport(note: SavedNote) { const blob = new Blob([`${note.title}\n\n${note.content}`], { type: "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = `${note.title.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "") || "docdoe-note"}.txt`; anchor.click(); URL.revokeObjectURL(url); } const subjects = Array.from(new Set(notes.map((note) => note.subject).filter((value): value is string => Boolean(value)))).sort(); const topics = Array.from(new Set(notes.map((note) => note.topic).filter((value): value is string => Boolean(value)))).sort(); const filteredNotes = notes.filter( (note) => (!subjectFilter || note.subject === subjectFilter) && (!topicFilter || note.topic === topicFilter) && (!sourceFilter || note.source === sourceFilter), ); return (

Your saved notes

Answers you saved from StudyChat and notes generated from your lessons. Stored on this device.

{openNote ? (

Open note

{openNote.title}

{[openNote.subject, openNote.topic, SOURCE_LABEL[openNote.source]].filter(Boolean).join(" · ")}

{openNote.content}

) : null} {notes.length > 0 ? (
) : null} {notes.length === 0 ? (

No notes saved yet

Ask a doubt in Study Chat and press "Save as note" on the answer, or use the notes generator from any lesson.

Make your first note
) : (
{filteredNotes.map((note) => (
{note.title} {SOURCE_LABEL[note.source]} {note.provenance === "starter" ? " · starter/sample" : ""} {` · ${new Date(note.at).toLocaleDateString()}`}

{note.content}

Regenerate Send to StudyChat Turn into quiz Turn into flashcards
))} {filteredNotes.length === 0 ? (
No saved notes match these filters.
) : null}
)}
); }