Advertisement
MaMonza

file-upload.component.ts

May 15th, 2025 (edited)
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 5.35 KB | Source Code | 0 0
  1. import { CommonModule } from '@angular/common';
  2. import { HttpClient, HttpErrorResponse, HttpEventType } from '@angular/common/http';
  3. import { Component, computed, inject, input, signal } from '@angular/core';
  4. import { FormsModule } from '@angular/forms';
  5. import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
  6. import { faUpload, faFileAlt, faExclamationTriangle, faCheckCircle, faSpinner, faTimesCircle, faCloudUploadAlt, faTrash, faL, faEraser, faIndianRupeeSign } from '@fortawesome/free-solid-svg-icons';
  7. import { v4 as uuidv4 } from 'uuid';
  8.  
  9. export interface UploadFile {
  10.   file: File;
  11.   uuid: string,
  12.   baseName: string,
  13.   extension: string,
  14.   customName?: string;
  15.   progress: number;
  16.   status: 'pending' | 'uploading' | 'done' | 'error' | 'invalid';
  17.   errorMessage?: string;
  18. }
  19.  
  20. @Component({
  21.   selector: 'app-file-upload',
  22.   standalone: true,
  23.   imports: [FormsModule, FontAwesomeModule, CommonModule],
  24.   templateUrl: `./file-upload.component.html`,
  25.   styles: ``
  26. })
  27. export default class FileUploadComponent {
  28.  
  29.   http = inject(HttpClient);
  30.   ALLOWED_EXTENSIONS = input<string[]>([], { alias: 'allowedExts' });
  31.   MAX_FILE_SIZE_MB = input<number>(5, { alias: 'maxFileSize' });
  32.  
  33.   cloudUpload = faCloudUploadAlt;
  34.   fileAlt = faFileAlt;
  35.   exclTriangle = faExclamationTriangle;
  36.   checkCircle = faCheckCircle;
  37.   spinner = faSpinner;
  38.   timesCircle = faTimesCircle;
  39.   uploadIcon = faUpload;
  40.   trash = faTrash;
  41.   clear = faEraser;
  42.  
  43.   files = signal<UploadFile[]>([]);
  44.   isDragging = signal<boolean>(false);
  45.   isUploaded = signal<boolean>(false);
  46.  
  47.   allowedExtensionsInputList = computed(() => {
  48.     return this.ALLOWED_EXTENSIONS().toString();
  49.   });
  50.  
  51.   allowedExtensionsStr = computed(() => {
  52.     return this.allowedExtensionsInputList().replaceAll('.', ' ');
  53.   });
  54.  
  55.   maxFileSize = computed(() => this.MAX_FILE_SIZE_MB() * 1024 * 1024);
  56.  
  57.   onDragOver(event: DragEvent) {
  58.     event.preventDefault();
  59.     this.isDragging.set(true);
  60.   }
  61.  
  62.   onDragLeave(event: DragEvent) {
  63.     event.preventDefault();
  64.     this.isDragging.set(false);
  65.   }
  66.  
  67.   onDrop(event: DragEvent) {
  68.     event.preventDefault();
  69.     this.isDragging.set(false);
  70.  
  71.     const files = Array.from(event.dataTransfer?.files || []);
  72.     if (files.length) {
  73.       this.addFiles(files);
  74.     }
  75.   }
  76.  
  77.   addFiles(selected: File[]) {
  78.     const uploads = selected.map(file => this.validateFile(file)).filter(file => file !== null);
  79.     this.files.update(files => [...files, ...uploads]);
  80.     this.isUploaded.set(false);
  81.   }
  82.  
  83.   removeFile(selected: UploadFile) {
  84.     this.files.update(files => files.filter(f => f.file !== selected.file));
  85.   }
  86.  
  87.   clearFiles() {
  88.     this.files.set([]);
  89.     this.isUploaded.set(false);
  90.   }
  91.  
  92.   onFilesSelected(event: Event) {
  93.     const input = event.target as HTMLInputElement;
  94.     const selected = Array.from(input.files || []);
  95.     this.addFiles(selected);
  96.   }
  97.  
  98.   validateFile(file: File): UploadFile | null {
  99.     const lastDotIndex: number = file.name.lastIndexOf('.');
  100.     const baseName: string = file.name.substring(0, lastDotIndex);
  101.     const extension: string = file.name.substring(lastDotIndex).toLowerCase();
  102.  
  103.     const newFile: UploadFile = { file, uuid: uuidv4(), baseName, extension, customName: file.name, progress: 0, status: 'pending', errorMessage: '' };
  104.  
  105.     if (!this.ALLOWED_EXTENSIONS().includes(extension)) {
  106.       return { ...newFile, status: 'invalid', errorMessage: 'Estensione non consentita' };
  107.     }
  108.  
  109.     if (file.size > this.maxFileSize()) {
  110.       return { ...newFile, status: 'invalid', errorMessage: `File troppo grande (max ${this.MAX_FILE_SIZE_MB()}MB)` };
  111.     }
  112.  
  113.     if (this.files()
  114.       .some(existing =>
  115.         existing.baseName === baseName &&
  116.         existing.extension === extension &&
  117.         existing.file.size === file.size
  118.       ))
  119.       return null;
  120.  
  121.     return newFile;
  122.   }
  123.  
  124.   updateCustomName(upload: UploadFile) {
  125.     upload.customName = `${upload.baseName}${upload.extension}`;
  126.   }
  127.  
  128.   sanitizeBaseName(upload: UploadFile) {
  129.     const ext = upload.extension.toLowerCase();
  130.     const extPattern = new RegExp(`${ext.replace('.', '\\.')}`, 'gi');
  131.     upload.baseName = upload.baseName.replace(extPattern, '');
  132.     upload.baseName = upload.baseName.replace(/[\\/:*?"<>|]/g, '');
  133.    upload.baseName = upload.baseName.trim();
  134.    this.updateCustomName(upload);
  135.  }
  136.  
  137.  uploadAll() {
  138.    this.files().filter(f => f.status === 'pending').forEach(file => this.uploadFile(file));
  139.    this.isUploaded.set(true);
  140.  }
  141.  
  142.  uploadFile(upload: UploadFile) {
  143.  
  144.    this.updateCustomName(upload);
  145.  
  146.    const formData = new FormData();
  147.    formData.append('files', upload.file);
  148.    formData.append('path', '');
  149.    formData.append('saveAs', upload.customName!);
  150.  
  151.    upload.status = 'uploading';
  152.  
  153.    this.http.post('http://localhost:7777/api/upload/files', formData, {
  154.      reportProgress: true,
  155.      observe: 'events'
  156.    }).subscribe({
  157.      next: (event) => {
  158.        if (event.type === HttpEventType.UploadProgress && event.total) {
  159.          upload.progress = Math.round(100 * event.loaded / event.total);
  160.        } else if (event.type === HttpEventType.Response) {
  161.          upload.status = 'done';
  162.        }
  163.      },
  164.      error: (err: HttpErrorResponse) => {
  165.        upload.status = 'error';
  166.        upload.errorMessage = err.error;
  167.        console.error(err);
  168.      }
  169.    });
  170.  }
  171.  
  172. }
  173.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement