'use client' import { useRouter } from 'next/navigation' import { cn } from '@/lib/utils' import { useLanguage } from '@/lib/i18n' import React, { useEffect, useState } from 'react' import { motion, AnimatePresence } from 'motion/react' import { getAllNotes, getNotesWithReminders, toggleReminderDone } from '@/app/actions/notes' import { useBrainstormSessions, useDeleteBrainstorm } from '@/hooks/use-brainstorm' import { ChevronRight, Lock, Plus, Pencil, Trash2, Sparkles, Clock, Pin, PinOff, GripVertical, FileText, Folder, FolderOpen, } from 'lucide-react' export function NoteLink({ title, isActive, isPinned, onClick, }: { title: string; isActive: boolean; isPinned?: boolean; onClick: () => void }) { const { language } = useLanguage() const slideX = language === 'fa' || language === 'ar' ? 10 : -10 return ( {title} {isPinned && } ) } export function SidebarBrainstorms() { const { data: sessions, isLoading } = useBrainstormSessions() const deleteBrainstorm = useDeleteBrainstorm() const router = useRouter() const { t } = useLanguage() if (isLoading) { return (
{[1, 2, 3].map(i =>
)}
) } if (!sessions || sessions.length === 0) { return (

{t('brainstorm.noSessions')}

) } return (
{sessions.slice(0, 10).map(s => (
{(s as any)._owned !== false && ( )}
))}
) } export function SidebarReminders({ onOpenNote }: { onOpenNote: (noteId: string, notebookId: string | null) => void }) { const { t } = useLanguage() const [reminders, setReminders] = useState< { id: string; title: string | null; reminder: Date | string | null; isReminderDone: boolean; notebookId: string | null }[] >([]) const [loading, setLoading] = useState(true) const [togglingId, setTogglingId] = useState(null) const reload = () => { getNotesWithReminders().then((rows) => setReminders(rows as typeof reminders)) } useEffect(() => { let cancelled = false setLoading(true) getNotesWithReminders().then((rows) => { if (!cancelled) setReminders(rows as typeof reminders) }).finally(() => { if (!cancelled) setLoading(false) }) return () => { cancelled = true } }, []) const handleComplete = async (e: React.MouseEvent, noteId: string) => { e.stopPropagation(); setTogglingId(noteId) await toggleReminderDone(noteId, true) setReminders(prev => prev.map(r => r.id === noteId ? { ...r, isReminderDone: true } : r)) setTogglingId(null) } const handleSnooze = async (e: React.MouseEvent, noteId: string) => { e.stopPropagation() const snoozeDate = new Date(Date.now() + 60 * 60 * 1000) setTogglingId(noteId) try { await fetch(`/api/notes/${noteId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reminder: snoozeDate.toISOString(), isReminderDone: false }) }) setReminders(prev => prev.map(r => r.id === noteId ? { ...r, reminder: snoozeDate, isReminderDone: false } : r)) } catch (e) { console.error('[silent-catch]', e); reload() } setTogglingId(null) } if (loading) { return (
{[1, 2, 3].map((i) =>
)}
) } const now = new Date() const active = reminders.filter((r) => !r.isReminderDone && r.reminder) const overdue = active.filter((r) => new Date(r.reminder!) < now) const upcoming = active.filter((r) => new Date(r.reminder!) >= now) if (active.length === 0) { return (

{t('reminders.emptyDescription')}

) } const renderItem = (note: (typeof active)[0], overdueItem?: boolean) => (
) return (
{overdue.length > 0 && (

{t('reminders.overdue')}

{overdue.map((n) => renderItem(n, true))}
)} {upcoming.length > 0 && (

{t('reminders.upcoming')}

{upcoming.map((n) => renderItem(n))}
)}
) } export function SidebarCarnetItem({ carnet, isActive, notes, activeNoteId, onCarnetClick, onNoteClick, onAddSubNotebook, onRename, onDelete, onTogglePin, isPinned, children, isDragging, dragHandleProps, level, isExpanded, toggleExpand, hasChildNotebooks, hasActiveDescendant, }: { carnet: { id: string; name: string; initial: string; isPrivate?: boolean } isActive: boolean notes: { id: string; title: string; isPinned?: boolean }[] activeNoteId: string | null onCarnetClick: () => void onNoteClick: (noteId: string, carnetId: string) => void onAddSubNotebook: () => void onRename: () => void onDelete: () => void onTogglePin: () => void isPinned: boolean children?: React.ReactNode isDragging?: boolean dragHandleProps?: React.HTMLAttributes level: number isExpanded: boolean toggleExpand: () => void hasChildNotebooks?: boolean hasActiveDescendant?: boolean }) { const { t, language } = useLanguage() const isRtl = language === 'fa' || language === 'ar' const hasChildren = hasChildNotebooks || React.Children.count(children) > 0 || notes.length > 0 const [contextMenu, setContextMenu] = useState<{ x: number; y: number } | null>(null) useEffect(() => { if (!contextMenu) return const handler = () => setContextMenu(null) window.addEventListener('click', handler) return () => window.removeEventListener('click', handler) }, [contextMenu]) return (
{ e.preventDefault(); e.stopPropagation(); setContextMenu({ x: e.clientX, y: e.clientY }) }} > {level > 0 &&
} {level > 0 &&
}
e.stopPropagation()}>
{hasChildren ? ( ) :
} { e.stopPropagation(); onRename() }} className={cn( 'flex-1 flex items-center gap-2.5 px-2 py-1.5 rounded-lg transition-all duration-300 group/item cursor-pointer relative overflow-hidden', isActive ? 'bg-white dark:bg-white/10 shadow-sm border border-border/40' : 'hover:bg-white/40 dark:hover:bg-white/5' )}> {isActive && }
{isExpanded ? : }
{carnet.name} {carnet.isPrivate && } {!isActive && hasActiveDescendant && }
{notes.length > 0 && ( {notes.length} )}
{isPinned && }
{contextMenu && ( e.stopPropagation()} >
)} {isExpanded && (
{children} {isExpanded && notes.map(note => ( onNoteClick(note.id, carnet.id)} /> ))} {isExpanded && notes.length === 0 && !hasChildren && (

{t('sidebar.notebookEmpty')}

)}
)}
) }