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:
| Option | Type | Default | Description |
|---|---|---|---|
allowedTypes | string[] | PDF, DOCX, PPTX | Array of allowed MIME types |
bucketName | string | 'PDF' | Storage bucket name |
makePublic | boolean | false | Whether uploaded files should be public |
onUploadSuccess | (fileUrl: string) => void | - | Callback when upload succeeds |