Adding new user information from Firebase v8 to v9 - javascript

I have a code to create user with image and username to Firebase v8 and I can't replace it to Firebase v9.
Can someone help me? Thank you!
import { useState, useEffect } from 'react'
import { projectAuth, projectStorage, projectFirestore } from '../firebase/config'
import { useAuthContext } from './useAuthContext'
export const useSignup = () => {
const [isCancelled, setIsCancelled] = useState(false)
const [error, setError] = useState(null)
const [isPending, setIsPending] = useState(f`enter code here`alse)
const { dispatch } = useAuthContext()
// upload user thumbnail
const uploadPath = `thumbnails/${res.user.uid}/${thumbnail.name}`
const img = await projectStorage.ref(uploadPath).put(thumbnail)
const imgUrl = await img.ref.getDownloadURL()
// add display AND PHOTO_URL name to user
await res.user.updateProfile({ displayName, photoURL: imgUrl })

import {st, db} from '../firebase/config'
import { getDownloadURL, ref, uploadBytesResumable } from 'firebase/storage';
import { doc, setDoc } from 'firebase/firestore';
const _storageRef = ref(st, "thumbnails/" + res.user.uid + "/" + thumbnail.name)
const _uploadTask = uploadBytesResumable(_storageRef, file);
_uploadTask.on("state_changed", (snapshot) => {
console.log((snapshot.bytesTransferred/snapshot.totalBytes) * 100)
},(error) => {
console.error(error)
}, async () => {
await getDownloadURL(_storageRef)
.then((url) => {
//update database with the new image url
console.log(url)
//setDoc(doc(db, "users", uid), {
// photoURL: url
// }, {merge: true}) <- to not erase the rest of the values like displayName
})
.catch(error => console.error(error))
})

The documentation has examples of both V8 (namespaced) and V9 (Modular) syntax. You can just switch to modular tab for reference. For this case, try refactoring the code as shown below:
import { ref, uploadBytes } from "firebase/storage"
import { updateProfile } from "firebase/auth"
const storageRef = ref(projectStorage, `thumbnails/${res.user.uid}/${thumbnail.name}`);
// 'file' comes from the Blob or File API
// uploadBytes() instead of .put()
uploadBytes(storageRef, file).then(async (snapshot) => {
console.log('Uploaded a blob or file!');
// updateProfile() is now a top-level function
// and not a method on User object
await updateProfile(res.user, {
displayName: name
});
console.log("User profile updated")
});
Also do ensure that you've initialized auth and storage using getAuth() and getStorage() respectively.
Checkout:
Upload files with Cloud Storage on Web
Update user profile using Firebase Modular SDK

Related

Couldn't add firebase storage download url in same firestore document in React Js

I'm trying to upload multiple images to firebase storage and store those urls in one firestore document as an array of strings, but I couldn't add all urls in same firestore document. Instead it's creating different documents for each firebase storage Url.
ImageUpload.js
import React, { useState } from "react";
import { toast } from "react-toastify";
import { db, storage } from "../firebase.config";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import {collection ,addDoc ,arrayUnion ,FieldValue ,updateDoc} from "firebase/firestore";
import { useNavigate } from "react-router-dom";
import "./style.css";
function ImageUpload() {
const [allImages, setAllImages] = useState([]);
function handleAllImage(e) {
e.preventDefault();
setAllImages(e.target.files);
console.log(e.target.files);
}
function MutipleUpload(e) {
e.preventDefault();
try {
const docRef = collection(db, "products");
{
for (let i = 0; i < allImages.length; i++) {
const storageRef = ref(storage, `productImages/${allImages[i].name}`);
const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
contentType: allImages[i].type,
});
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
},
(error) => toast.error(error.message),
() => {
getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) => {
await addDoc(docRef, {
imgUrl: arrayUnion(downloadURL),
});
}
);
}
);
}
}
toast.success("product added successfully!");
} catch (error) {
console.log(error.message);
}
}
return (
<>
<input
type="file"
multiple="multiple"
onChange={handleAllImage}
required
/>
<button onClick={MutipleUpload} type="submit" className="buy__btn mt-3">
Add Image
</button>
</>
);
}
export default ImageUpload;
Extra text cause error "It looks like your post is mostly code; please add some more details."
The problem is in this code:
getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) => {
await addDoc(docRef, {
imgUrl: arrayUnion(downloadURL),
});
}
);
Every time you call addDoc, Firestore create a new document in the collection.
If you instead want update an existing document, you have to:
Remember the document ID for the document you want to update.
Then call updateDoc on that document
To generate a document ID once and then update that all the time, have a look at the third code snippet in the documentation on adding a document:
In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc():
import { collection, doc, setDoc } from "firebase/firestore";
// Add a new document with a generated id
const newCityRef = doc(collection(db, "cities"));
// later...
await setDoc(newCityRef, data);
Applied to your use-case, that could look something like this:
const docRef = collection(db, "products");
const newDocRef = doc(docRef); // 👈 generate reference to a single new doc
{
for (let i = 0; i < allImages.length; i++) {
const storageRef = ref(storage, `productImages/${allImages[i].name}`);
const uploadTask = uploadBytesResumable(storageRef, allImages[i], {
contentType: allImages[i].type,
});
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
},
(error) => toast.error(error.message),
() => {
getDownloadURL(uploadTask.snapshot.ref).then(
async (downloadURL) => {
await setDoc(newDocRef, { // 👈 Call setDoc, since the doc may not exist yet
imgUrl: arrayUnion(downloadURL),
}, { merge: true }); // 👈 tell it to merge values into any existing doc
}
);
}
);
}
}

How to use Firebase to upload images in Next.js?

I'm following a video tutorial about Nextjs and have seen that the version of Firebase he is using is out of date. I managed to follow all the steps reading the documentation until I got to this point.
Searched here and found some interesting answers on how to achieve the option to upload images to Firebase. Here the link
Have tried all solutions and none of them have worked. I get an error message:
FirebaseError: Firebase Storage: An unknown error occurred, please check the error payload for server response. (storage/unknown)
Bad Request
Here the code I'm trying:
import Image from "next/image";
import { useSession } from "next-auth/react";
import { FaceSmileIcon } from "#heroicons/react/24/outline";
import { VideoCameraIcon, PhotoIcon } from "#heroicons/react/20/solid";
import { useRef } from "react";
import { db, storage } from "../firebase";
import { collection, addDoc, serverTimestamp, doc, setDoc } from "firebase/firestore";
import { useState } from "react";
import {ref, uploadString, getDownloadURL, getStorage} from "firebase/storage";
function InputBox() {
const {data: session} = useSession();
const inputRef = useRef(null);
const filePickerRef = useRef(null);
const [imageToPost, setImageToPost] = useState(null);
const sendPost = async (e) => {
e.preventDefault();
if(!inputRef.current.value) return;
const colRef = collection(db, "posts")
await addDoc(colRef, {
message: inputRef.current.value,
name: session.user.name,
email: session.user.email,
image: session.user.image,
timestamp: serverTimestamp(),
}).then((document) => {
if(imageToPost) {
const storageRef = ref(storage, `posts/${document.id}`);
uploadString(storageRef, imageToPost, "data_url").then((snapshot) => {
getDownloadURL(snapshot.ref).then(URL => {
setDoc(doc(db, "posts", document.id),
{imageToPost: URL}, {merge: true}
);
});
})
removeImage();
}
})
inputRef.current.value = "";
};
const addImageToPost = (e) => {
const reader = new FileReader();
if(e.target.files[0]) {
reader.readAsDataURL(e.target.files[0]);
}
reader.onload = (readerEvent) => {
setImageToPost(readerEvent.target.result);
}
};
const removeImage = () => {
setImageToPost(null);
};
return ( <HERE THE REST OF THE CODE>
Don't be mad at me. I really tried to do my best to find a solution and to not post here.
Any help will be really appreciated because I can't figure out what is wrong, because as mentioned before I tried all options I found so far.
BTW also tried to assign storage to getStorage() before const storageRef = ref(storage, `posts/${document.id}`);
Like so:
.then((document) => {
if(imageToPost) {
const storage = getStorage();
const storageRef = ref(storage, `posts/${document.id}`);
<MORE CODE>
And my firebase.jsfile:
import { initializeApp } from 'firebase/app';
import { getStorage } from "firebase/storage";
const firebaseConfig = {
apiKey: "APIKEY-HERE",
authDomain: "AUTHDOMAIN-HERE",
projectId: "PROJECT-ID-HERE",
storageBucket: "STORAGE-BUCKET-HERE",
messagingSenderId: "MESSAGING-SENDER-HERE",
appId: "APPID-HERE"
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const storage = getStorage(app);
export { db, storage };
Try this, this worked for me: Firebase: "^9.0.0"
addDoc(dbInstance, {
message: inputRef.current.value,
name: session?.user?.name,
email: session?.user?.email,
image: session?.user?.image,
timestamp: serverTimestamp(),
}).then((doc) => {
if (imageToPost) {
const storageRef = ref(storage, `posts/${doc.id}`);
uploadString(storageRef, imageToPost, "data_url").then((snapshot) => {
getDownloadURL(snapshot.ref).then((url) => {
addDoc(dbInstance, { postImage: url });
});
});
removeImage();
}
});
inputRef.current.value = "";
Try this. I have used firebase v8.6.3.
const docRef = firebase.firestore().collection("colection_name").doc();
const storageRef = firebase.storage().ref();
const uploadTask = storageRef.child('/posts/' + imageToPost.name).put(imageToPost);
console.log(uploadTask)
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
(snapshot) => {
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
switch (snapshot.state) {
case firebase.storage.TaskState.PAUSED: // or 'paused'
console.log('Upload is paused');
break;
case firebase.storage.TaskState.RUNNING: // or 'running'
console.log('Upload is running');
break;
}
},
(error) => {
// A full list of error codes is available at
// https://firebase.google.com/docs/storage/web/handle-errors
switch (error.code) {
case 'storage/unauthorized':
// User doesn't have permission to access the object
break;
case 'storage/canceled':
// User canceled the upload
break;
// ...
case 'storage/unknown':
// Unknown error occurred, inspect error.serverResponse
break;
}
},
() => {
// Upload completed successfully, now we can get the download URL
uploadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
console.log('File available at', downloadURL);
docRef.set({
message: inputRef.current.value,
name: session.user.name,
email: session.user.email,
image: downloadURL,
});
});
}
);
If you don't want the upload progress and error then you can get rid of that codes and directly proceed to getDownloadURL.

Firebase Firestore not deleting a document

I want to delete document in firestore using deleteDoc(), but this not delete.
It's my code:
import { getFirestore } from "firebase/firestore";
import { getStorage, ref } from "firebase/storage";
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
let stRootDocument = `/${tipo}/${uid}`;
const refCol = doc(db,stRootDocument);
deleteDoc(refCol)
.then(() => {
console.log("Entire Document has been deleted successfully.")
})
.catch(error => {
console.log(error);
})
although, this dont delete.
My document don't have any subcollections, but don't delete, also I have tried:
to do the refer using:
const refCol = doc(db,"carousel","xgxxxxxxxxxxxxxxx");
and after to pass this refer in the deleteDoc Method but too don't delete.
other form:
deleteDoc(doc(colRef,uid)).then((objR) => {
return objR;
}).catch((error) => {
console.log(error);
});
but, this too doesn't delete.

error in firebase function, Firebase: No Firebase App '[DEFAULT]' has been created

I'm trying to interact with the database in a function, but I'm getting an error when trying to use the doc() function within a firebase function
The error im getting is: " Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
"
See the code below and the function I'm getting the error on.
Im guessing in has something to do with not being able to use the db variable? But if I cant do that, how do I interact with the database?
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import {
collectionGroup, doc, getDoc,
getDocs,
getFirestore,
query,
} from "firebase/firestore";
// Sendgrid Config
import sgMail from "#sendgrid/mail";
import {
ClientUserData,
Course,
EventType,
Task,
} from "../../src/views/types/interfaces";
import {startOfDay} from "date-fns";
const adminApp = admin.initializeApp();
const auth = adminApp.auth();
const db = getFirestore();
//THE FUNCTION IT FAILS ON
export const checkCourseForNewClientProgram = functions.pubsub.schedule("Every day").onRun(async () => {
const courses: Course[] = [];
const coursesByCompanies = query(collectionGroup(db, "courses"));
// eslint-disable-next-line max-len
const checkCourseForNewClientProgramSnapshot = await getDocs(coursesByCompanies);
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {
const course = courseSnapshot.data() as Course;
if (course.events && course.events.length > 0) {
const courseEvents = course.events;
const todayDate = startOfDay(new Date()).getTime();
courseEvents.forEach((event) => {
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
// eslint-disable-next-line max-len
const eventStart = convertFirebaseDateIntoJSDate(event.start.seconds).getTime();
if (todayDate === eventStart) {
courses.push(course);
}
if (event.type === EventType.TASK) {
const eventLessons = (event as Task).lessons;
if (eventLessons && eventLessons.length > 0) {
eventLessons.forEach((eventLesson) => {
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
// eslint-disable-next-line max-len
const lessonStart = convertFirebaseDateIntoJSDate(eventLesson.start.seconds).getTime();
if (todayDate === lessonStart) {
courses.push(course);
}
});
}
}
});
}
});
let userIds: string[] = [];
courses.forEach((course) => {
if (course.users) {
userIds = course.users.map((userId) => userId);
}
});
const userEmails = await Promise.all(
userIds.map(async (userId) => {
// eslint-disable-next-line max-len
const userData = await getDocumentFromId<ClientUserData>("company_clients", userId);
return userData.email;
})
);
await Promise.all(
userEmails.map(async (userEmail) => {
const msg = {
to: userEmail,
from: "nicky#byplayart.dk",
templateId: "d-8609d087e96e42d5abe6991d19afb22d",
dynamic_template_data: {
email: userEmail,
toName: "Testing tasks",
fromName: "Unlimited Performance",
subject: "Du har en opgave der venter",
text: "Dette er din tekst",
},
};
try {
await sgMail.send(msg);
return {
success: true,
};
} catch (e) {
return {
success: false,
error: e,
};
}
})
);
});
With the Admin SDK version 9 you should use the namespaced syntax, similarly to the Client SDK v8. The corresponding reference for the Admin DSK is actually the Node.js one.
Your code should then been adapted as follows:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
const db = admin.firestore();
export const checkCourseForNewClientProgram = functions.pubsub.schedule("Every day").onRun(async () => {});
const coursesByCompanies = db.collectionGroup("courses");
const checkCourseForNewClientProgramSnapshot = await coursesByCompanies.get();
checkCourseForNewClientProgramSnapshot.forEach((courseSnapshot) => {...});
//...
return null;
});
Don't forget to correctly terminate your Cloud Function, either by returning the Promise returned by the last Promise.all() call or a value (e.g. return null;) after all the asynchronous work is complete. This is a key point and I would suggest you read this part of the doc and watch the 3 videos about "JavaScript Promises" from the Firebase video series.

While running my next.js app that is using solidity smart contracts, I am getting "Cannot read properties of undefined" error

I was running my next.js app and trying to fetch user I am getting "cannot read properties of undefined" error
And following error in the console
Below is the code I was using
import Ewitter from './Ewitter.json';
import ethers from 'ethers';
import { useState, useEffect } from 'react';
const ContractABI = Ewitter.abi;
const ContractAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
const Ethereum = typeof window !== 'undefined' && (window as any).ethereum;
const getEwitterContract = () => {
const provider = new ethers.providers.Web3Provider(Ethereum);
const signer = provider.getSigner();
const EwitterContract = new ethers.Contract(
ContractAddress,
ContractABI,
signer
);
return EwitterContract;
};
const useEwitter = () => {
// const Ewitter = getEwitterContract();
const [currentAccount, setCurrentAccount] = useState<string>('');
const [currentUser, setCurrentUser] = useState<string>('');
const connect = async () => {
try {
if (!Ethereum) {
alert('Please install MetaMask');
return;
}
const accounts = await Ethereum.request({
method: 'eth_requestAccounts',
});
if (accounts.length === 0) {
alert('Please unlock MetaMask');
return;
}
const account = accounts[0];
console.log('connected to account: ', account);
setCurrentAccount(account);
} catch (errors) {
console.log(errors);
}
};
useEffect(() => {
if(!Ethereum){
console.log("No ethereum wallet found, please install metamask")
return ;
}
connect();
}, []);
useEffect(() =>{
if(currentAccount){
getUser();
}
}, [currentAccount])
const getUser = async ()=>{
const contract = getEwitterContract();
const user = await contract.getUser(currentAccount);
const {avatar, bio, name, username, wallet} = user;
console.log(user);
return user;
}
return { connect, account: currentAccount };
};
export default useEwitter;
#Update1
I've changed import ethers from 'ethers' to import {ethers} from 'ethers' and now I'm facing this error
If unable to understand properly or if you want to see the whole codebase then this is the link to the github repo
https://github.com/ChiragDogra/ewitter/blob/userIssue/dapp/hooks/useEwitter.ts
believe or not I just had that issue.
the problem is how you are importing ethers. Should be
import { ethers } from "ethers";

Categories

Resources