Skip to content

Instantly share code, notes, and snippets.

@AllanJeremy
Last active November 6, 2023 12:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AllanJeremy/dd5398b1416ac02393a8d896cdcbfe14 to your computer and use it in GitHub Desktop.
Save AllanJeremy/dd5398b1416ac02393a8d896cdcbfe14 to your computer and use it in GitHub Desktop.
Firebase extension of Quasar's QUploader component (that performs firebase uploads)
/** This component is now maintained via the [quasar-helpers repo](https://github.com/AllanJeremy/quasar-helpers) */
import { createUploaderComponent } from "quasar";
import { computed, ref, watch } from "vue";
// Firebase stuff
import {
getDownloadURL,
ref as firebaseRef,
uploadBytesResumable,
} from "@firebase/storage";
import { storage } from "../../firebase"; // or import {getStorage} from '@firebase/storage'
//? importing 👆 from local firebase file because it is attached to our app ~ `storage` here is the value returned by getStorage(firebaseApp)
// Export a Vue component
export default createUploaderComponent({
// defining the QUploader plugin here
name: "FirebaseUploader", // your component's name
props: {
/** Whether all inputs should be blocked when upload is in progress or not */
blocking: {
type: Boolean,
default: true,
},
/** The firebase storage directory your files will be uploaded to */
//! This assumes that each instance of FirebaseUploader will only upload to a specific directory - customization implementation would be worth considering
directory: {
type: String,
default: "/",
},
},
emits: [
// ...your custom events name list
],
injectPlugin({ props, emit, helpers }) {
let uploadTaskList = ref([]);
let uploadProgressList = ref([]);
let uploadInProgress = ref(false);
let uploadedFiles = ref([]);
// Using watcher because computed isn't triggered when the progress list array is updated
watch(
() => uploadProgressList,
() => {
uploadInProgress.value = false;
if (uploadProgressList.value.length) {
uploadInProgress.value = uploadProgressList.value.reduce(
(prev, curr) => prev || curr,
false
);
// Uploads complete - emit uploaded event with file details
emit("uploaded", uploadedFiles);
}
},
{ deep: true }
);
// [ REQUIRED! ]
// We're working on uploading files
const isUploading = computed(() => uploadInProgress.value);
/** Shows overlay on top of the
uploader signaling it's waiting
on something (blocks all controls) */
const isBusy = computed(() => {
return props.blocking ? uploadInProgress.value : false;
});
// [ REQUIRED! ]
// Cancel all uploads
function abort() {
uploadTaskList.value.forEach((uploadTask) => {
uploadTask.cancel();
});
}
// [ REQUIRED! ]
// Start the uploading process
function upload() {
// Reset uploads
uploadTaskList.value = [];
uploadProgressList.value = [];
helpers.queuedFiles.value.forEach((fileToUpload, i) => {
// No point uploading the file if it has already been uploaded before
if (helpers.uploadedFiles.value.includes(fileToUpload)) return;
//? 👇 This can be whatever you want ~ can use UUID to generate unique file names
const fileName = `${Date.now()}-${fileToUpload.name}`;
const storageRef = firebaseRef(
storage,
`${props.directory}/${fileName}`
);
const uploadTask = uploadBytesResumable(storageRef, fileToUpload);
uploadTaskList.value = [...uploadTaskList.value, uploadTask];
uploadTask.on(
"state_changed",
(snapshot) => {
helpers.updateFileStatus(
fileToUpload,
"uploading",
snapshot.bytesTransferred
);
uploadProgressList.value[i] = snapshot.state === "running";
},
(err) => {
console.error(
"Something went wrong while trying to upload the file.",
err
);
helpers.updateFileStatus(
fileToUpload,
"failed",
uploadTask.snapshot.bytesTransferred
);
uploadProgressList.value[i] = false;
},
async () => {
const uploadUrl = await getDownloadURL(uploadTask.snapshot.ref);
// The upload for all files will be accessible when all files are done uploading
uploadedFiles.value.push({
originalFile: fileToUpload,
uploadUrl,
});
const { bytesTransferred } = uploadTask.snapshot;
helpers.updateFileStatus(
fileToUpload,
"uploaded",
bytesTransferred
);
helpers.uploadedFiles.value = [
...helpers.uploadedFiles.value,
fileToUpload,
];
helpers.uploadedSize.value += bytesTransferred;
uploadProgressList.value[i] = false;
}
);
});
}
return {
isUploading,
isBusy,
abort,
upload,
};
},
});
@AllanJeremy
Copy link
Author

AllanJeremy commented Nov 6, 2023

Just seen these comments now. A little too late :(
Turning this into a repo @guswelter . Thanks y'all!

Created a repo with the same

@AllanJeremy
Copy link
Author

@saro-saravanan , really sorry I saw this late amidst the flood of github notifications.
I'm really happy you got to resolve it and I have pushed your suggestion in the repo :)

Feel free to fork the repo and create PRs in case you have any suggestions :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment