import { api } from '../api.js'; export class FileUploadView extends HTMLElement { constructor() { super(); this.folderId = null; this.handleEscape = this.handleEscape.bind(this); } connectedCallback() { document.addEventListener('keydown', this.handleEscape); } disconnectedCallback() { document.removeEventListener('keydown', this.handleEscape); } setFolder(folderId) { this.folderId = folderId; this.render(); this.attachListeners(); this.openFileSelector(); } render() { const folderInfo = this.folderId ? `(Folder ID: ${this.folderId})` : '(Root)'; this.innerHTML = ` `; } openFileSelector() { const fileInput = this.querySelector('#file-input'); if (fileInput) { fileInput.click(); } } attachListeners() { const fileInput = this.querySelector('#file-input'); const backBtn = this.querySelector('#upload-back-btn'); if (backBtn) { backBtn.addEventListener('click', () => this.close()); } if (fileInput) { fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { const view = this.querySelector('.file-upload-view'); if (view) { view.style.display = 'flex'; } this.handleFiles(e.target.files); } else { this.close(); } }); fileInput.addEventListener('cancel', () => { this.close(); }); } } handleEscape(e) { if (e.key === 'Escape') { this.close(); } } close() { window.history.back(); } hide() { document.removeEventListener('keydown', this.handleEscape); this.remove(); } async handleFiles(files) { const uploadList = this.querySelector('#upload-list'); if (!uploadList) return; for (const file of files) { const itemId = `upload-${Date.now()}-${Math.random()}`; const item = document.createElement('div'); item.className = 'upload-item'; item.id = itemId; item.innerHTML = `
${file.name}
${this.formatFileSize(file.size)}
Uploading...
`; uploadList.appendChild(item); try { await this.uploadFile(file, itemId); const statusEl = item.querySelector('.upload-item-status'); if (statusEl) { statusEl.textContent = 'Complete'; statusEl.classList.add('success'); } } catch (error) { const statusEl = item.querySelector('.upload-item-status'); if (statusEl) { statusEl.textContent = 'Failed: ' + error.message; statusEl.classList.add('error'); } } } this.dispatchEvent(new CustomEvent('upload-complete', { bubbles: true })); setTimeout(() => { this.close(); }, 1500); } async uploadFile(file, itemId) { const formData = new FormData(); formData.append('file', file); if (this.folderId !== null && this.folderId !== undefined) { formData.append('folder_id', String(this.folderId)); } const xhr = new XMLHttpRequest(); return new Promise((resolve, reject) => { xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable) { const percentComplete = (e.loaded / e.total) * 100; const item = this.querySelector(`#${itemId}`); if (item) { const progressFill = item.querySelector('.progress-fill'); if (progressFill) { progressFill.style.width = percentComplete + '%'; } } } }); xhr.addEventListener('load', () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error(xhr.statusText)); } }); xhr.addEventListener('error', () => reject(new Error('Upload failed'))); xhr.addEventListener('abort', () => reject(new Error('Upload aborted'))); xhr.open('POST', '/files/upload'); xhr.setRequestHeader('Authorization', `Bearer ${api.getToken()}`); xhr.send(formData); }); } formatFileSize(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'; if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB'; return (bytes / 1073741824).toFixed(1) + ' GB'; } } customElements.define('file-upload-view', FileUploadView);