I am creating a Post based application where a user can post pictures and text. I want to save the images on Firebase Storage bucket and get the image link immediately and store the image and the photo description text to my database
I am using Node, Express and Mongo DB . Below is my Code
import ModalStyles from "./_createpost.module.scss";
import {
ref,
uploadBytes,
getDownloadURL
} from "firebase/storage";
import { storage } from "../../../config/firebaseConfig";
import { faCamera, faPhotoFilm } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useContext, useEffect, useState } from "react";
import UserContext from "../../../context/userContext";
import { uuid } from "uuidv4";
import { v4 } from "uuid";
import axios from "axios";
interface IModalProps {
}
const Modal = ({ }: IModalProps) => {
const user = useContext(UserContext)
const [imageUpload, setImageUpload] = useState<FileList | null>({} as FileList);
const [postDesc, setPostDesc] = useState<string>('');
const [imageUrls, setImageUrls] = useState<Array<string>>([]);
const convertToBlob = (file: File): Promise<Blob> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
const blob = new Blob([reader.result as ArrayBuffer], { type: file.type });
resolve(blob);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
};
const uploadImages = async () => {
if (!imageUpload) return;
let promises: string[] = [];
for (let index = 0; index < imageUpload.length; index++) {
/*
const { name, type } = imageUpload[index];
const file = new File([name], name, { type: type });
const blob = await convertToBlob(file);
*/
const blob = await convertToBlob(imageUpload[index]);
const imageRef = ref(storage, `images/${imageUpload[index].name + v4()}`);
uploadBytes(imageRef, blob).then((snapshot) => {
getDownloadURL(snapshot.ref).then((urls) => {
console.log(urls);
promises.push(urls)
setImageUrls(prev => [...prev, urls]);
});
}).catch(err => console.log('An Error Occured!', err))
}
return promises;
};
const uploadFile = async (e: React.FormEvent) => {
e.preventDefault();
const imgs = uploadImages();
console.log(imgs);
if (!imgs) return;
try {
const response = await axios.post(`http://localhost:5000/post/create`, { creator_id: "64af540d576b8737651135a4", post_description: postDesc, photos: imgs });
if (response.data) console.log('image uploaded successfully');
} catch (error) {
console.log('An Error occured while uploading the post');
}
}
const onchange = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
setImageUpload(files);
}
return <div className={ModalStyles.modal__container}>
<h4 className={ModalStyles.modal__title}>Create Post</h4>
<div className={`divider ${ModalStyles.modal__divider}`}></div>
<div>
<div className={`${ModalStyles.post__post_header} mt-1`}>
<img src={user.profilePixs} className={ModalStyles.post__user_pixs} alt={user.firstname} />
<div className={ModalStyles.post__post_info}>
<p className={ModalStyles.post__user_name}>{user.firstname} {user.lastname}</p>
<p>Public</p>
</div>
</div>
<form className={ModalStyles.modal__post_inputField} onSubmit={uploadFile}>
<textarea name="post_desc" id="post_desc" className={ModalStyles.modal__description} value={postDesc} onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setPostDesc(e.target.value)}></textarea>
<div className={`divider ${ModalStyles.modal__divider}`}></div>
<p className={ModalStyles.modal__addPhotoText}>
<span> Add to your Post</span>
<FontAwesomeIcon icon={faPhotoFilm} size="2xl" className={ModalStyles.modal__addPhotoIcon} />
<input type="file" name="photo" id="photo" multiple onChange={onchange} accept="image/png, image/jpeg" className={ModalStyles.modal__addPhotoIcon} />
</p>
<input type="submit" value="Post" className={ModalStyles.modal__submitBtn} />
</form>
</div>
</div>;
};
export default Modal;
It always return an empty ARRAY of the images from the Promise.
Then after sending and EMPTY ARRAY to my DB, the urls are return. I know its due to Async function but I cant figure how to make it fininsh the first request before the next one as I want the urls to be available before making the next move
Tried the above code but no way forward