'use client' import { useState, useCallback } from 'react' import { motion, AnimatePresence } from 'motion/react' import { Sparkles, X, CheckCircle2, FolderPlus, Folder, ChevronDown, ChevronUp, Loader2, AlertCircle, Check } from 'lucide-react' import { cn } from '@/lib/utils' import { analyzeNotebookForOrganization, executeNotebookOrganization, type OrganizationGroup, type OrganizationPlan, } from '@/app/actions/organize-notebook' import { toast } from 'sonner' import { useLanguage } from '@/lib/i18n' interface OrganizeNotebookDialogProps { open: boolean onOpenChange: (open: boolean) => void notebookId: string notebookName: string onDone?: () => void } type Step = 'idle' | 'analyzing' | 'preview' | 'executing' | 'done' export function OrganizeNotebookDialog({ open, onOpenChange, notebookId, notebookName, onDone, }: OrganizeNotebookDialogProps) { const { t, language } = useLanguage() const organizePanelSlide = language === 'fa' || language === 'ar' ? -60 : 60 const [step, setStep] = useState('idle') const [plan, setPlan] = useState(null) const [editableGroups, setEditableGroups] = useState([]) const [expandedGroups, setExpandedGroups] = useState>(new Set()) const [error, setError] = useState(null) const [result, setResult] = useState<{ created: number; moved: number } | null>(null) const handleAnalyze = useCallback(async () => { setStep('analyzing') setError(null) setPlan(null) const res = await analyzeNotebookForOrganization(notebookId) if (!res.success || !res.plan) { setError(res.error ?? t('organizeNotebook.unknownError')) setStep('idle') return } setPlan(res.plan) setEditableGroups(res.plan.groups.map(g => ({ ...g, notes: [...g.notes] }))) setExpandedGroups(new Set(res.plan.groups.map((_, i) => i))) setStep('preview') }, [notebookId]) const handleRenameGroup = (idx: number, name: string) => { setEditableGroups(prev => prev.map((g, i) => i === idx ? { ...g, name } : g)) } const handleToggleNote = (groupIdx: number, noteId: string) => { setEditableGroups(prev => prev.map((g, i) => { if (i !== groupIdx) return g const has = g.notes.some(n => n.id === noteId) return { ...g, notes: has ? g.notes.filter(n => n.id !== noteId) : g.notes, } })) } const handleRemoveGroup = (idx: number) => { setEditableGroups(prev => prev.filter((_, i) => i !== idx)) } const toggleExpand = (idx: number) => { setExpandedGroups(prev => { const next = new Set(prev) next.has(idx) ? next.delete(idx) : next.add(idx) return next }) } const handleExecute = useCallback(async () => { if (!plan) return setStep('executing') const finalPlan: OrganizationPlan = { notebookId: plan.notebookId, groups: editableGroups.filter(g => g.notes.length > 0 && g.name.trim()), } const res = await executeNotebookOrganization(finalPlan) if (!res.success) { setError(res.error ?? t('organizeNotebook.unknownError')) setStep('preview') return } setResult({ created: res.created, moved: res.moved }) setStep('done') toast.success(t('organizeNotebook.toastSuccess', { created: res.created, moved: res.moved })) onDone?.() }, [plan, editableGroups, onDone]) const handleClose = () => { if (step === 'analyzing' || step === 'executing') return onOpenChange(false) // Reset after close animation setTimeout(() => { setStep('idle') setPlan(null) setEditableGroups([]) setError(null) setResult(null) }, 300) } if (!open) return null const totalNotes = editableGroups.reduce((acc, g) => acc + g.notes.length, 0) const newSubNbs = editableGroups.filter(g => g.isNew).length return ( {open && ( <> {/* Backdrop */} {/* Panel */} e.stopPropagation()} > {/* Header */}

{t('organizeNotebook.title')}

{notebookName}

{/* Content */}
{/* IDLE */} {step === 'idle' && ( {error && (

{error}

)}

{t('organizeNotebook.intro')}

    {[t('organizeNotebook.bulletThemes'), t('organizeNotebook.bulletSubfolders'), t('organizeNotebook.bulletPreview')].map(item => (
  • {item}
  • ))}
)} {/* ANALYZING */} {step === 'analyzing' && (

{t('organizeNotebook.analyzingTitle')}

{t('organizeNotebook.analyzingSubtitle')}

{[0, 1, 2].map(i => ( ))}
)} {/* PREVIEW */} {step === 'preview' && ( {/* Summary bar */}

{t('organizeNotebook.previewSummary', { groups: editableGroups.length, notes: totalNotes, newSubs: newSubNbs, })}

{error && (

{error}

)} {/* Groups */}
{editableGroups.map((group, idx) => ( {/* Group header */}
{group.isNew ? : }
handleRenameGroup(idx, e.target.value)} className="flex-1 bg-transparent text-[12px] font-semibold text-ink outline-none focus:text-brand-accent transition-colors min-w-0" /> {group.isNew && ( {t('organizeNotebook.badgeNew')} )}
{/* Notes list */} {expandedGroups.has(idx) && (
{group.notes.map(note => (
handleToggleNote(idx, note.id)} >
{note.title || t('organizeNotebook.untitledNote')}
))}
)}
{/* Collapsed count */} {!expandedGroups.has(idx) && (
{t('organizeNotebook.notesInGroup', { count: group.notes.length })}
)}
))}
)} {/* EXECUTING */} {step === 'executing' && (

{t('organizeNotebook.executingTitle')}

{t('organizeNotebook.executingSubtitle')}

)} {/* DONE */} {step === 'done' && (

{t('organizeNotebook.doneTitle')}

{result && (

{t('organizeNotebook.doneStats', { created: result.created, moved: result.moved })}

)}
)}
{/* Footer actions */}
{step === 'idle' && ( )} {step === 'preview' && (
)} {step === 'done' && ( )}
)}
) }