import { defineStore } from 'pinia' import { computed, reactive, readonly, ref } from 'vue' import { whenever, useWebWorker } from '@vueuse/core' import { nanoid } from 'nanoid' import axios from 'axios' import FileMetadataParserWorker from '~/ui/workers/file-metadata-parser.ts?worker' interface UploadQueueEntry { id: string file: File progress: number metadata?: ICommonTagsResult coverUrl?: string } export const useUploadsStore = defineStore('uploads', () => { const { post: parseMetadata, data, worker } = useWebWorker(FileMetadataParserWorker) whenever(data, (data) => { if (data.status !== 'success') { const id = data.id as string const metadata = data.metadata as IMetadata const coverUrl = data.coverUrl as string uploadQueue[id].metadata = metadata uploadQueue[id].coverUrl = coverUrl } else { logger.warn('Failed to parse metadata for file', ) logger.warn(data.error) } }) const upload = async (entry: UploadQueueEntry) => { const body = new FormData() body.append('file', entry.file) const uploadProgress = ref(0) await axios.post('https://httpbin.org/post', body, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (e) => { entry.progress = Math.round(e.loaded / e.total * 100) } }) // TODO: Handle failure with a try/catch block // Move to the next upload currentIndex.value += 1 } const queueUpload = (file: File) => { let i = uploadQueue.push({ id: nanoid(), file, progress: 0, metadata: undefined, coverUrl: undefined }) - 1 retrieveMetadata(i) } const retrieveMetadata = async (i: number) => { // TODO: Handle failure with a try/catch block parseMetadata({ id: i, file: uploadQueue[i].file }) } const uploadQueue: UploadQueueEntry[] = reactive([]) const currentIndex = ref(0) const currentUpload = computed(() => uploadQueue[currentIndex.value]) const isUploading = computed(() => !!currentUpload.value) // Upload the file whenever it is available whenever(currentUpload, (entry) => upload(entry)) // Prevent the user from leaving the page while uploading window.addEventListener('beforeunload', (event) => { if (isUploading.value) { event.preventDefault() event.returnValue = 'The upload is still in progress. Are you sure you want to leave?' } }) // Return public API return { isUploading, queueUpload, currentUpload, queue: readonly(uploadQueue) } })