123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- import { ReactiveVar } from 'meteor/reactive-var';
- import { Tracker } from 'meteor/tracker';
- /**
- * Global upload progress manager for drag-and-drop file uploads
- * Tracks upload progress across all cards and provides reactive data
- */
- class UploadProgressManager {
- constructor() {
- // Map of cardId -> array of upload objects
- this.cardUploads = new ReactiveVar(new Map());
- // Map of uploadId -> upload object for easy lookup
- this.uploadMap = new ReactiveVar(new Map());
- }
- /**
- * Add a new upload to track
- * @param {string} cardId - The card ID
- * @param {Object} uploader - The uploader object from Attachments.insert
- * @param {File} file - The file being uploaded
- * @returns {string} uploadId - Unique identifier for this upload
- */
- addUpload(cardId, uploader, file) {
- const uploadId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
- const upload = {
- id: uploadId,
- cardId: cardId,
- file: file,
- uploader: uploader,
- progress: new ReactiveVar(0),
- status: new ReactiveVar('uploading'), // 'uploading', 'completed', 'error'
- error: new ReactiveVar(null),
- startTime: Date.now(),
- endTime: null
- };
- // Update card uploads
- const currentCardUploads = this.cardUploads.get();
- const cardUploads = currentCardUploads.get(cardId) || [];
- cardUploads.push(upload);
- currentCardUploads.set(cardId, cardUploads);
- this.cardUploads.set(currentCardUploads);
- // Update upload map
- const currentUploadMap = this.uploadMap.get();
- currentUploadMap.set(uploadId, upload);
- this.uploadMap.set(currentUploadMap);
- // Set up uploader event listeners
- uploader.on('progress', (progress) => {
- upload.progress.set(progress);
- });
- uploader.on('uploaded', (error, fileRef) => {
- upload.status.set(error ? 'error' : 'completed');
- upload.endTime = Date.now();
- upload.error.set(error);
- if (process.env.DEBUG === 'true') {
- console.log(`Upload ${uploadId} completed:`, error ? 'error' : 'success');
- }
- // Remove from tracking after a delay to show completion
- setTimeout(() => {
- this.removeUpload(uploadId);
- }, 2000);
- });
- uploader.on('error', (error) => {
- upload.status.set('error');
- upload.endTime = Date.now();
- upload.error.set(error);
- if (process.env.DEBUG === 'true') {
- console.log(`Upload ${uploadId} failed:`, error);
- }
- // Remove from tracking after a delay to show error
- setTimeout(() => {
- this.removeUpload(uploadId);
- }, 3000);
- });
- if (process.env.DEBUG === 'true') {
- console.log(`Added upload ${uploadId} for card ${cardId}: ${file.name}`);
- }
- return uploadId;
- }
- /**
- * Remove an upload from tracking
- * @param {string} uploadId - The upload ID to remove
- */
- removeUpload(uploadId) {
- const upload = this.uploadMap.get().get(uploadId);
- if (!upload) return;
- const cardId = upload.cardId;
- // Remove from card uploads
- const currentCardUploads = this.cardUploads.get();
- const cardUploads = currentCardUploads.get(cardId) || [];
- const filteredCardUploads = cardUploads.filter(u => u.id !== uploadId);
- if (filteredCardUploads.length === 0) {
- currentCardUploads.delete(cardId);
- } else {
- currentCardUploads.set(cardId, filteredCardUploads);
- }
- this.cardUploads.set(currentCardUploads);
- // Remove from upload map
- const currentUploadMap = this.uploadMap.get();
- currentUploadMap.delete(uploadId);
- this.uploadMap.set(currentUploadMap);
- if (process.env.DEBUG === 'true') {
- console.log(`Removed upload ${uploadId} from tracking`);
- }
- }
- /**
- * Get all uploads for a specific card
- * @param {string} cardId - The card ID
- * @returns {Array} Array of upload objects
- */
- getUploadsForCard(cardId) {
- return this.cardUploads.get().get(cardId) || [];
- }
- /**
- * Get upload count for a specific card
- * @param {string} cardId - The card ID
- * @returns {number} Number of active uploads
- */
- getUploadCountForCard(cardId) {
- return this.getUploadsForCard(cardId).length;
- }
- /**
- * Check if a card has any active uploads
- * @param {string} cardId - The card ID
- * @returns {boolean} True if card has active uploads
- */
- hasActiveUploads(cardId) {
- return this.getUploadCountForCard(cardId) > 0;
- }
- /**
- * Get all uploads across all cards
- * @returns {Array} Array of all upload objects
- */
- getAllUploads() {
- const allUploads = [];
- this.cardUploads.get().forEach(cardUploads => {
- allUploads.push(...cardUploads);
- });
- return allUploads;
- }
- /**
- * Clear all uploads (useful for cleanup)
- */
- clearAllUploads() {
- this.cardUploads.set(new Map());
- this.uploadMap.set(new Map());
- }
- }
- // Create global instance
- const uploadProgressManager = new UploadProgressManager();
- export default uploadProgressManager;
|