Gallery Component with Upload Tracking
This gallery component now includes comprehensive upload tracking functionality that allows developers to monitor upload progress, completion, and errors in real-time.
Features
- Real-time Upload Progress: Track upload progress with percentage completion
- Upload Status Tracking: Monitor upload status (uploading, completed, error)
- Event-driven Architecture: Listen to upload events for custom handling
- Visual Progress Indicators: Beautiful loading UI with progress bars
- Error Handling: Comprehensive error tracking and display
- Multiple Upload Support: Handle multiple simultaneous uploads
Components
1. Upload Loading Component (cdtr-upload-loading)
A visual component that displays upload progress in the top-right corner of the screen.
Features:
- Animated progress bars
- Status indicators (uploading, completed, error)
- Auto-dismissal after completion
- Manual close button
- Multiple upload support
2. Enhanced Gallery Component (cdtr-gallery)
The main gallery component with integrated upload tracking.
New Properties:
uploadStatus: Object tracking upload status for each file
New Events:
upload-start: Fired when upload begins
upload-progress: Fired during upload progress
upload-complete: Fired when upload completes
upload-error: Fired when upload fails
Usage
Basic Implementation
<cdtr-upload-loading></cdtr-upload-loading>
document.addEventListener('upload-start', (event) => {
const { uploadId, fileName, file } = event.detail;
console.log(`Upload started: ${fileName}`);
});
document.addEventListener('upload-progress', (event) => {
const { uploadId, fileName, progress } = event.detail;
console.log(`Progress: ${fileName} - ${progress}%`);
});
document.addEventListener('upload-complete', (event) => {
const { uploadId, fileName, result } = event.detail;
console.log(`Upload completed: ${fileName}`);
});
document.addEventListener('upload-error', (event) => {
const { uploadId, fileName, error } = event.detail;
console.error(`Upload failed: ${fileName}`, error);
});
Advanced Implementation
class MyUploadHandler {
constructor() {
this.activeUploads = new Map();
this.setupEventListeners();
}
setupEventListeners() {
document.addEventListener('upload-start', this.handleUploadStart.bind(this));
document.addEventListener('upload-progress', this.handleUploadProgress.bind(this));
document.addEventListener('upload-complete', this.handleUploadComplete.bind(this));
document.addEventListener('upload-error', this.handleUploadError.bind(this));
}
handleUploadStart(event) {
const { uploadId, fileName, file } = event.detail;
this.activeUploads.set(uploadId, {
fileName,
file,
startTime: Date.now(),
status: 'uploading'
});
this.updateUploadButton(true);
this.showNotification(`Starting upload: ${fileName}`);
}
handleUploadProgress(event) {
const { uploadId, fileName, progress } = event.detail;
const upload = this.activeUploads.get(uploadId);
if (upload) {
upload.progress = progress;
}
this.updateProgressBar(uploadId, progress);
}
handleUploadComplete(event) {
const { uploadId, fileName, result } = event.detail;
const upload = this.activeUploads.get(uploadId);
if (upload) {
upload.status = 'completed';
upload.endTime = Date.now();
upload.duration = upload.endTime - upload.startTime;
}
this.updateUploadButton(false);
this.showNotification(`Upload completed: ${fileName}`, 'success');
setTimeout(() => {
this.activeUploads.delete(uploadId);
}, 3000);
}
handleUploadError(event) {
const { uploadId, fileName, error } = event.detail;
const upload = this.activeUploads.get(uploadId);
if (upload) {
upload.status = 'error';
upload.error = error;
}
this.updateUploadButton(false);
this.showNotification(`Upload failed: ${fileName}`, 'error');
setTimeout(() => {
this.activeUploads.delete(uploadId);
}, 5000);
}
updateUploadButton(isUploading) {
const button = document.querySelector('#uploadButton');
if (button) {
button.disabled = isUploading;
button.textContent = isUploading ? 'Uploading...' : 'Upload';
}
}
updateProgressBar(uploadId, progress) {
const progressBar = document.querySelector(`#progress-${uploadId}`);
if (progressBar) {
progressBar.style.width = `${progress}%`;
}
}
showNotification(message, type = 'info') {
console.log(`${type.toUpperCase()}: ${message}`);
}
getActiveUploads() {
return Array.from(this.activeUploads.values());
}
getUploadStatus(uploadId) {
return this.activeUploads.get(uploadId);
}
}
const uploadHandler = new MyUploadHandler();
Custom Upload Implementation
If you need to implement your own upload logic while still using the tracking system:
class CustomUploader {
async uploadFile(file) {
const uploadId = `${file.name}-${Date.now()}`;
this.dispatchUploadEvent('upload-start', {
uploadId,
fileName: file.name,
file
});
try {
const result = await this.performUpload(file, (progress) => {
this.dispatchUploadEvent('upload-progress', {
uploadId,
fileName: file.name,
progress
});
});
this.dispatchUploadEvent('upload-complete', {
uploadId,
fileName: file.name,
result
});
return result;
} catch (error) {
this.dispatchUploadEvent('upload-error', {
uploadId,
fileName: file.name,
error
});
throw error;
}
}
async performUpload(file, onProgress) {
return new Promise((resolve, reject) => {
let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 20;
if (progress >= 100) {
progress = 100;
clearInterval(interval);
onProgress(progress);
resolve({ success: true, url: 'https://example.com/uploaded-file.jpg' });
} else {
onProgress(Math.round(progress));
}
}, 200);
});
}
dispatchUploadEvent(type, detail) {
document.dispatchEvent(new CustomEvent(type, {
detail,
bubbles: true,
composed: true
}));
}
}
Event Details
upload-start
{
uploadId: string,
fileName: string,
file: File
}
upload-progress
{
uploadId: string,
fileName: string,
progress: number
}
upload-complete
{
uploadId: string,
fileName: string,
result: object
}
upload-error
{
uploadId: string,
fileName: string,
error: Error
}
Styling
The upload loading component uses CSS custom properties for theming:
cdtr-upload-loading {
--upload-bg-color: white;
--upload-border-color: #e0e0e0;
--upload-progress-color: #007bff;
--upload-success-color: #28a745;
--upload-error-color: #dc3545;
}
Browser Support
- Modern browsers with ES6+ support
- Requires LitElement framework
- Event-driven architecture for maximum compatibility
Examples
See upload-example.js for a complete working example of how to implement upload tracking in your application.