import { create } from 'zustand' import { libraryApi } from './api' import type { DocumentMeta, DocumentUpdateRequest } from './types' interface LibraryState { documents: DocumentMeta[] total: number isLoading: boolean error: string | null searchQuery: string // Selection selectedIds: Set toggleSelection: (id: string) => void clearSelection: () => void selectAll: () => void // Actions fetchDocuments: (query?: string) => Promise fetchTrash: () => Promise uploadDocument: (file: File) => Promise deleteDocument: (id: string, permanent?: boolean) => Promise restoreDocument: (id: string) => Promise bulkDelete: (permanent?: boolean) => Promise bulkRestore: () => Promise emptyTrash: () => Promise setSearchQuery: (query: string) => void updateDocument: (id: string, data: DocumentUpdateRequest) => Promise } function errorMessage(reason: unknown, fallback = 'Something went wrong.') { if (reason instanceof Error && reason.message) return reason.message; if (typeof reason === 'object' && reason !== null && 'error' in reason) { const error = reason.error; if (typeof error === 'object' && error !== null && 'message' in error && typeof error.message === 'string') { return error.message; } } return fallback; } export const useLibrary = create((set, get) => ({ documents: [], total: 0, isLoading: false, error: null, searchQuery: '', selectedIds: new Set(), toggleSelection: (id) => set((state) => { const newSelection = new Set(state.selectedIds) if (newSelection.has(id)) newSelection.delete(id) else newSelection.add(id) return { selectedIds: newSelection } }), clearSelection: () => set({ selectedIds: new Set() }), selectAll: () => set((state) => ({ selectedIds: new Set(state.documents.map(d => d.id)) })), setSearchQuery: (query) => set({ searchQuery: query }), fetchDocuments: async (query = '') => { set({ isLoading: true, error: null, searchQuery: query }) try { const data = await libraryApi.getDocuments(query) set({ documents: data.items, total: data.total, isLoading: false }) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) } }, fetchTrash: async () => { set({ isLoading: true, error: null, searchQuery: '' }) try { const data = await libraryApi.getTrash() set({ documents: data.items, total: data.total, isLoading: false }) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) } }, uploadDocument: async (file: File) => { set({ isLoading: true, error: null }) try { const newDoc = await libraryApi.uploadDocument(file) set((state) => ({ documents: [newDoc, ...state.documents], total: state.total + 1, isLoading: false })) return newDoc } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, deleteDocument: async (id: string, permanent = false) => { set({ isLoading: true, error: null }) try { await libraryApi.deleteDocument(id, permanent) set((state) => ({ documents: state.documents.filter(d => d.id !== id), total: state.total - 1, selectedIds: new Set(Array.from(state.selectedIds).filter(sid => sid !== id)), isLoading: false })) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, restoreDocument: async (id: string) => { set({ isLoading: true, error: null }) try { await libraryApi.restoreDocument(id) set((state) => ({ documents: state.documents.filter(d => d.id !== id), total: state.total - 1, selectedIds: new Set(Array.from(state.selectedIds).filter(sid => sid !== id)), isLoading: false })) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, bulkDelete: async (permanent = false) => { const { selectedIds } = get() if (selectedIds.size === 0) return set({ isLoading: true, error: null }) try { if (permanent) { // Must delete one by one if permanent await Promise.all(Array.from(selectedIds).map(id => libraryApi.deleteDocument(id, true))) } else { await libraryApi.bulkDelete({ ids: Array.from(selectedIds) }) } set((state) => ({ documents: state.documents.filter(d => !state.selectedIds.has(d.id)), total: state.total - state.selectedIds.size, selectedIds: new Set(), isLoading: false })) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, bulkRestore: async () => { const { selectedIds } = get() if (selectedIds.size === 0) return set({ isLoading: true, error: null }) try { await libraryApi.bulkRestore({ ids: Array.from(selectedIds) }) set((state) => ({ documents: state.documents.filter(d => !state.selectedIds.has(d.id)), total: state.total - state.selectedIds.size, selectedIds: new Set(), isLoading: false })) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, emptyTrash: async () => { set({ isLoading: true, error: null }) try { await libraryApi.emptyTrash() set({ documents: [], total: 0, selectedIds: new Set(), isLoading: false }) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } }, updateDocument: async (id: string, data: DocumentUpdateRequest) => { set({ isLoading: true, error: null }) try { const updatedDoc = await libraryApi.updateDocument(id, data) set((state) => ({ documents: state.documents.map(d => d.id === id ? updatedDoc : d), isLoading: false })) } catch (err: unknown) { set({ error: errorMessage(err), isLoading: false }) throw err } } }))