import React, { useMemo } from 'react' import { knowledgeGroupService } from '../../services/knowledgeGroupService' import { KnowledgeGroup, UpdateGroupData, CreateGroupData } from '../../types' import { Plus, Book, Library, MessageSquare, Trash2, Edit2, FolderInput, ChevronLeft, ChevronRight } from 'lucide-react' import { motion, AnimatePresence } from 'framer-motion' import { NotebookDetailView } from './NotebookDetailView' import { CreateNotebookDrawer } from '../CreateNotebookDrawer' import { EditNotebookDrawer } from '../EditNotebookDrawer' import { ImportFolderDrawer } from '../ImportFolderDrawer' import { useLanguage } from '../../contexts/LanguageContext' import { useToast } from '../../contexts/ToastContext' import { useConfirm } from '../../contexts/ConfirmContext' interface NotebooksViewProps { authToken: string onChatWithContext: (context: { selectedGroups?: string[], selectedFiles?: string[] }) => void isAdmin?: boolean } /** Flatten a tree of groups into a flat list */ function flattenGroups(groups: KnowledgeGroup[]): KnowledgeGroup[] { const result: KnowledgeGroup[] = []; function walk(items: KnowledgeGroup[]) { for (const g of items) { result.push(g); if (g.children?.length) walk(g.children); } } walk(groups); return result; } const PAGE_SIZE = 12; export const NotebooksView: React.FC = ({ authToken, onChatWithContext, isAdmin = false }) => { const { t } = useLanguage() const { showError } = useToast() const { confirm } = useConfirm() const [notebooks, setNotebooks] = React.useState([]) const [isLoading, setIsLoading] = React.useState(true) const [selectedNotebook, setSelectedNotebook] = React.useState(null) const [isCreateDrawerOpen, setIsCreateDrawerOpen] = React.useState(false) const [isImportDrawerOpen, setIsImportDrawerOpen] = React.useState(false) const [editingNotebook, setEditingNotebook] = React.useState(null) const [currentPage, setCurrentPage] = React.useState(1) // Flatten tree for display in the grid const flatNotebooks = useMemo(() => flattenGroups(notebooks), [notebooks]) const totalPages = Math.ceil(flatNotebooks.length / PAGE_SIZE) const paginatedNotebooks = useMemo(() => { const start = (currentPage - 1) * PAGE_SIZE; return flatNotebooks.slice(start, start + PAGE_SIZE); }, [flatNotebooks, currentPage]) const fetchNotebooks = async () => { try { const groups = await knowledgeGroupService.getGroups() setNotebooks(groups) } catch (error) { console.error(error) } finally { setIsLoading(false) } } React.useEffect(() => { fetchNotebooks() }, [authToken, selectedNotebook]) const handleCreateNotebook = async (data: CreateGroupData) => { try { setIsLoading(true) await knowledgeGroupService.createGroup(data) await fetchNotebooks() setIsCreateDrawerOpen(false) } catch (error) { console.error(error) showError(t('createFailed')) } finally { setIsLoading(false) } } const handleUpdateNotebook = async (id: string, data: UpdateGroupData) => { await knowledgeGroupService.updateGroup(id, data) await fetchNotebooks() } const handleDeleteNotebook = async (e: React.MouseEvent, id: string, name: string) => { e.stopPropagation() if (!(await confirm(t('confirmDeleteNotebook').replace('$1', name)))) return try { setIsLoading(true) await knowledgeGroupService.deleteGroup(id) setNotebooks(prev => flattenGroups(prev).filter(n => n.id !== id) as any) await fetchNotebooks() } catch (error) { console.error(error) showError(t('deleteFailed')) } finally { setIsLoading(false) } } if (selectedNotebook) { return ( setSelectedNotebook(null)} onChatWithContext={onChatWithContext} isAdmin={!!isAdmin} /> ) } return (

{t('navKnowledgeGroups')}

{t('notebooksDesc')}

{isAdmin && ( )} {isAdmin && ( )}
{isLoading ? (
) : flatNotebooks.length === 0 ? (

{t('noKnowledgeGroups')}

{t('createGroupDesc')}

{isAdmin && ( )}
) : (
{paginatedNotebooks.map((notebook) => ( setSelectedNotebook(notebook)} className="bg-white rounded-xl border border-slate-200/80 p-5 shadow-sm hover:shadow-md transition-all group relative overflow-hidden flex flex-col h-64 cursor-pointer" >
e.stopPropagation()}> {isAdmin && ( )} {isAdmin && ( )}

{notebook.parentId && } {notebook.name}

{notebook.description || t('noDescriptionProvided')}

{notebook.fileCount || 0} {t('files')}
{notebook.updatedAt ? new Date(notebook.updatedAt).toLocaleDateString() : ''}
))}
)}
{/* Pagination: always show when there are notebooks */} {flatNotebooks.length > 0 && (
{t('showingRange', (currentPage - 1) * PAGE_SIZE + 1, Math.min(currentPage * PAGE_SIZE, flatNotebooks.length), flatNotebooks.length)}
)} {isCreateDrawerOpen && ( setIsCreateDrawerOpen(false)} onCreate={handleCreateNotebook} /> )} {editingNotebook && ( setEditingNotebook(null)} notebook={editingNotebook} onUpdate={handleUpdateNotebook} /> )} setIsImportDrawerOpen(false)} authToken={authToken} onImportSuccess={fetchNotebooks} />
) }