apps/portal/app/composables/files/README.md

File Upload Composables

This directory contains composables related to file handling and uploading.

File Upload Composables

This directory contains composables related to file handling and uploading.

useFileDropUpload

A composable that provides file drop and upload functionality with progress tracking, error handling, and file validation.

Usage

<script setup>
import { useFileDropUpload } from '~/composables/files/useFileDropUpload';

const {
  // Refs
  selectedFile, // The currently selected file (File | null)
  isUploading, // Whether an upload is in progress (boolean)
  uploadProgress, // Upload progress percentage (number 0-100)
  uploadError, // Error message if upload failed (string | null)
  fileInputRef, // Ref to file input element (must be passed to input element)
  dropZoneRef, // Ref to drop zone element (must be passed to container element)
  isOverDropZone, // Whether user is dragging a file over the drop zone (boolean)
  uploadedFileUrl, // URL of the successfully uploaded file (string | null)

  // Methods
  resetUploadState, // Reset all state variables
  processFile, // Process a file (validation)
  handleUpload, // Start the upload process
  triggerFileInput, // Trigger file input click
  onFileSelect, // Handle file selection from input
  handleCancelUpload, // Cancel ongoing upload
  handleRetry, // Retry a failed upload
} = useFileDropUpload({
  // Options (all optional)
  allowedTypes: [
    // Array of allowed MIME types
    'application/pdf',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  ],
  bucketName: 'files', // Storage bucket name
  makePublic: false, // Whether the uploaded file should be public
  onUploadSuccess: (fileUrl) => {
    // Called when upload succeeds with the file URL
    console.log('File uploaded:', fileUrl);
  },
});
</script>

<template>
  <!-- Drop zone -->
  <div
    ref="dropZoneRef"
    :class="isOverDropZone ? 'border-blue-500 bg-blue-100' : 'border-gray-300 bg-gray-100'"
    class="rounded-lg border-2 border-dashed p-6 text-center">
    <p v-if="!selectedFile">Drag and drop a file here, or</p>
    <button @click="triggerFileInput">Select a file</button>

    <div v-if="isUploading">
      <p>Uploading: {{ uploadProgress }}%</p>
      <button @click="handleCancelUpload">Cancel</button>
    </div>

    <div v-if="uploadError">
      <p>Error: {{ uploadError }}</p>
      <button @click="handleRetry">Retry</button>
    </div>
  </div>

  <!-- Hidden file input -->
  <input ref="fileInputRef" type="file" class="hidden" @change="onFileSelect" />
</template>

Options

The useFileDropUpload composable accepts the following options:

OptionTypeDefaultDescription
allowedTypesstring[]PDF, DOCX, PPTXArray of allowed MIME types
bucketNamestring'PDF'Storage bucket name
makePublicbooleanfalseWhether uploaded files should be public
onUploadSuccess(fileUrl: string) => void-Callback when upload succeeds