113 lines
3.4 KiB
JavaScript
113 lines
3.4 KiB
JavaScript
import { ref } from 'vue';
|
|
import axios from 'axios';
|
|
|
|
/**
|
|
* Composable for handling file uploads.
|
|
*
|
|
* @param {Object} options
|
|
* @param {string[]} options.acceptedTypes - Array of accepted MIME types (default: ['image/*'])
|
|
* @param {number} options.maxSizeMB - Maximum file size in MB (default: 10)
|
|
* @param {string} options.category - Category for the upload (default: 'general')
|
|
*/
|
|
export function useFileUpload(options = {}) {
|
|
const acceptedTypes = options.acceptedTypes || ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
|
|
const maxSizeMB = options.maxSizeMB || 10;
|
|
const category = options.category || 'general';
|
|
|
|
const photoHashes = ref([]);
|
|
const isUploading = ref(false);
|
|
const uploadError = ref(null);
|
|
|
|
/**
|
|
* Upload a file to the server.
|
|
*
|
|
* @param {File} file
|
|
* @returns {Promise<Object|null>}
|
|
*/
|
|
const uploadFile = async (file) => {
|
|
// Validation
|
|
if (file.size > maxSizeMB * 1024 * 1024) {
|
|
uploadError.value = `File size exceeds ${maxSizeMB}MB limit.`;
|
|
return null;
|
|
}
|
|
|
|
const isAccepted = acceptedTypes.some(type => {
|
|
if (type.endsWith('/*')) {
|
|
const baseType = type.split('/')[0];
|
|
return file.type.startsWith(`${baseType}/`);
|
|
}
|
|
return file.type === type;
|
|
});
|
|
|
|
if (!isAccepted && acceptedTypes.length > 0) {
|
|
uploadError.value = 'Invalid file type.';
|
|
return null;
|
|
}
|
|
|
|
isUploading.value = true;
|
|
uploadError.value = null;
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
try {
|
|
const response = await axios.post(`/File/Upload/${category}`, formData, {
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data'
|
|
}
|
|
});
|
|
|
|
if (response.data && response.data.success && response.data.hashkey) {
|
|
const hashkey = response.data.hashkey;
|
|
photoHashes.value.push(hashkey);
|
|
return response.data;
|
|
} else {
|
|
throw new Error(response.data?.message || 'Upload failed');
|
|
}
|
|
} catch (err) {
|
|
console.error('Upload error:', err);
|
|
const status = err.response?.status;
|
|
const backendMsg = err.response?.data?.message || err.response?.data?.error;
|
|
if (status === 403) {
|
|
uploadError.value = "You don't have permission to upload files here.";
|
|
} else if (status === 413) {
|
|
uploadError.value = 'File too large.';
|
|
} else {
|
|
uploadError.value = backendMsg || err.message || 'Failed to upload file.';
|
|
}
|
|
return null;
|
|
} finally {
|
|
isUploading.value = false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Remove a hash from the list.
|
|
*
|
|
* @param {string} hash
|
|
*/
|
|
const removeHash = (hash) => {
|
|
photoHashes.value = photoHashes.value.filter(h => h !== hash);
|
|
};
|
|
|
|
/**
|
|
* Set initial hashes (e.g., when loading existing data).
|
|
*
|
|
* @param {string[]} hashes
|
|
*/
|
|
const setInitialHashes = (hashes) => {
|
|
if (Array.isArray(hashes)) {
|
|
photoHashes.value = [...hashes];
|
|
}
|
|
};
|
|
|
|
return {
|
|
photoHashes,
|
|
isUploading,
|
|
uploadError,
|
|
uploadFile,
|
|
removeHash,
|
|
setInitialHashes
|
|
};
|
|
}
|