// Dashboard functionality with unified collections architecture // Procedural/imperative style (no OOP) import type { SectionData, BookInfo } from './types/api'; const SCROLL_AMOUNT = 300; function scrollCarousel(collectionId: string, direction: number): void { const track = document.getElementById(`carousel-track-${collectionId}`) as HTMLElement; if (!track) return; const scrollAmount = direction * SCROLL_AMOUNT; track.scrollBy({ left: scrollAmount, behavior: 'smooth' }); } function openDashboardSettings(): void { const modal = document.getElementById('dashboard-settings-modal') as HTMLElement; if (modal) { modal.classList.remove('hidden'); } } function closeDashboardSettings(): void { const modal = document.getElementById('dashboard-settings-modal') as HTMLElement; if (modal) { modal.classList.add('hidden'); } } function toggleCollectionVisibility(collectionId: string): void { const checkbox = document.querySelector(`input[data-collection-id="${collectionId}"]`) as HTMLInputElement; if (checkbox) { checkbox.checked = !checkbox.checked; } } async function saveDashboardSettings(): Promise { const collectionList = document.getElementById('collection-list') as HTMLElement; if (!collectionList) return; const collectionItems = collectionList.querySelectorAll('[data-collection-id]') as NodeListOf; const hiddenCollections: string[] = []; const collectionOrder: string[] = []; collectionItems.forEach((item) => { const collectionId = item.dataset.collectionId; const checkbox = item.querySelector('input[type="checkbox"]') as HTMLInputElement; if (collectionId) { collectionOrder.push(collectionId); if (checkbox && !checkbox.checked) { hiddenCollections.push(collectionId); } } }); const itemsPerCollection = (document.querySelector('#items-count-display') as HTMLElement)?.textContent || '20'; try { const response = await (window as any).api.put('/dashboard/preferences', { library_id: new URLSearchParams(window.location.search).get('library_id') || '', hidden_collections: hiddenCollections, collection_order: collectionOrder, items_per_section: parseInt(itemsPerCollection), }); if (response.ok) { (window as any).showToast.success('Dashboard settings saved'); closeDashboardSettings(); window.location.reload(); } } catch (error) { (window as any).showToast.error('Failed to save settings'); console.error('Save dashboard settings error:', error); } } async function restoreSystemCollection(collectionName: string, collectionTitle: string): Promise { if (!confirm(`Are you sure you want to reset "${collectionTitle}" to its default state? Any customizations will be lost.`)) { return; } try { const response = await (window as any).api.post('/dashboard/restore-system-collection', { collection_name: collectionName, }); if (response.ok) { (window as any).showToast.success(`"${collectionTitle}" restored to defaults`); setTimeout(() => window.location.reload(), 1000); } } catch (error) { (window as any).showToast.error('Failed to restore system collection'); console.error('Restore system collection error:', error); } } async function switchLibrary(libraryId: string): Promise { const container = document.getElementById('collections-container') as HTMLElement; const loading = document.getElementById('loading-spinner') as HTMLElement; if (!container || !loading) return; loading.classList.remove('hidden'); try { const response = await fetch(`/api/dashboard/sections?library_id=${libraryId}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error('Failed to load sections'); } const data = await response.json(); renderCollections(data.sections); } catch (error) { (window as any).showToast.error('Failed to load library'); console.error('Switch library error:', error); } finally { loading.classList.add('hidden'); } } function renderCollections(sections: SectionData[]): void { const container = document.getElementById('collections-container') as HTMLElement; if (!container) return; container.innerHTML = sections.map(section => `
${section.icon}

${section.title}

${section.description ? `

${section.description}

` : ''}
${section.view_all_url ? `View All →` : ''}
`).join(''); } function renderBookCard(book: BookInfo): string { const coverUrl = book.cover_image_path || '/static/placeholder-book.svg'; return `
${book.title}

${book.title}

${book.author ? `

${book.author}

` : ''}
`; } function viewBook(bookId: string): void { console.log('View book:', bookId); } function reloadPage(): void { window.location.reload(); } function updateItemsCount(input: HTMLInputElement, targetId: string): void { const display = document.getElementById(targetId) as HTMLElement; if (display) { display.textContent = input.value; } } function initDragAndDrop(): void { const collectionList = document.getElementById('collection-list') as HTMLElement; if (!collectionList) return; let draggedItem: HTMLElement | null = null; collectionList.addEventListener('dragstart', (e: Event) => { const target = e.target as HTMLElement; if (target.classList.contains('collection-item')) { draggedItem = target; target.style.opacity = '0.5'; } }); collectionList.addEventListener('dragend', (e: Event) => { const target = e.target as HTMLElement; if (target.classList.contains('collection-item')) { target.style.opacity = '1'; draggedItem = null; } }); collectionList.addEventListener('dragover', (e: Event) => { e.preventDefault(); const target = e.target as HTMLElement; if (target.classList.contains('collection-item') && target !== draggedItem && draggedItem) { const rect = target.getBoundingClientRect(); const midY = rect.top + rect.height / 2; if ((e as DragEvent).clientY < midY) { target.parentNode?.insertBefore(draggedItem, target); } else { if (target.parentNode) { target.parentNode.insertBefore(draggedItem, target.nextSibling); } } } }); } document.addEventListener('DOMContentLoaded', () => { initDragAndDrop(); document.addEventListener('click', (e: Event) => { const target = e.target as HTMLElement; const actionElem = target.closest('[data-action]') as HTMLElement; const action = actionElem?.getAttribute('data-action'); switch (action) { case 'scroll-carousel': { const collectionId = target.dataset.collectionId || actionElem?.dataset.collectionId; const direction = parseInt(target.dataset.direction || actionElem?.dataset.direction || '0'); if (collectionId) scrollCarousel(collectionId, direction); break; } case 'open-dashboard-settings': openDashboardSettings(); break; case 'close-dashboard-settings': closeDashboardSettings(); break; case 'toggle-collection-visibility': { const checkbox = target as HTMLInputElement; const colId = checkbox.dataset.collectionId; if (colId) toggleCollectionVisibility(colId); break; } case 'save-dashboard-settings': saveDashboardSettings(); break; case 'restore-system-collection': { const colName = actionElem?.dataset.collectionName || target.dataset.collectionName; const colTitle = actionElem?.dataset.collectionTitle || target.dataset.collectionTitle || 'System Collection'; if (colName) restoreSystemCollection(colName, colTitle); break; } case 'view-book': { const bookId = target.dataset.bookId || actionElem?.dataset.bookId; if (bookId) viewBook(bookId); break; } case 'reload-page': reloadPage(); break; case 'switch-library': { const select = target as HTMLSelectElement; if (select.value) switchLibrary(select.value); break; } case 'update-items-count': { const input = target as HTMLInputElement; const displayTarget = input.getAttribute('target'); if (displayTarget) updateItemsCount(input, displayTarget); break; } } }); }); export {};