| 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 instanceconst uploadProgressManager = new UploadProgressManager();export default uploadProgressManager;
 |