why I receive null after push new notes to firebase (realtime database) - firebase

I push new info for user in category folder.
If I do it in version 8 like this:
const category = await firebase.database().ref(`/users/${uid}/categories`).push({title, limit})
I can receive feedback with information about notes (title, limit, and also special key, that added in firebase) in const category.
But when I use version 9, my const category is null..
However request work correctly, and in database I can see pushed info with special key.
async createCategory({ commit, dispatch }, { title, limit }) {
try {
const uid = await dispatch('getUid')
const db = getDatabase();
const postListRef = ref(db, `/users/${uid}/categories`);
const newPostRef = push(postListRef);
const category = await set(newPostRef, {title, limit});
return {title, limit, id: category.key}
} catch (e) {
commit('setError', e)
throw e
}
}
How to receive feedback from database after push new info? (in const category)
I want have {title, limit, id: category.key}

Related

Unable to transfer NEAR tokens between accounts using near-api-js

I am trying to transfer NEAR tokens between 2 testnet wallets using the near-api-js library in NextJS
Running send money function of the account, I am getting the following error
import { connect, keyStores } from "near-api-js";
export const NearConfig = async () => {
const config = {
networkId: "testnet",
keyStore: new keyStores.BrowserLocalStorageKeyStore(),
nodeUrl: "https://rpc.testnet.near.org",
walletUrl: "https://wallet.testnet.near.org",
helperUrl: "https://helper.testnet.near.org",
explorerUrl: "https://explorer.testnet.near.org",
};
return await connect(config);
};
setNear(await NearConfig());
const sendTokens = async () => {
try {
const account = await near.account(account_id);
await account.sendMoney(
"itissandeep98.testnet", // receiver account
"100000000" // amount in yoctoNEAR
);
} catch (error) {
console.log(error);
showAlert(error.message, "error");
}
};
On running account.getAccessKeys(); there are full access keys as well as functional access keys available, then why I am not able to send tokens?
Moreover, I don't understand the below screenshot from the docs(https://docs.near.org/docs/develop/front-end/introduction); why isn't it allowed?
Found this after one week of struggle: Connect FullAccess account with near-api-js
const PENDING_ACCESS_KEY_PREFIX = "pending_key";
const loginFullAccess = async (options) => {
const currentUrl = new URL(window.location.href);
const newUrl = new URL(wallet._walletBaseUrl + "/login/");
newUrl.searchParams.set('success_url', options.successUrl || currentUrl.href);
newUrl.searchParams.set('failure_url', options.failureUrl || currentUrl.href);
const accessKey = KeyPair.fromRandom("ed25519");
newUrl.searchParams.set("public_key", accessKey.getPublicKey().toString());
await wallet._keyStore.setKey(
wallet._networkId,
PENDING_ACCESS_KEY_PREFIX + accessKey.getPublicKey(),
accessKey
);
window.location.assign(newUrl.toString());
};
After login you can use the sendMoney function to transfer NEAR tokens between accounts
I wanted to open up near website asking user for permissions required for sending the tokens. Was struggling till I noticed this text in nearjs doc regarding account.sendMoney:
Hint
Use WalletConnection in the browser to redirect to NEAR Wallet for
Account/key management using the BrowserLocalStorageKeyStore.
Basically, instead of nearConnection needed to use walletConnection
// const account = await nearConnection.account(accountId) // Wrong
const account = await walletConnection.account() // Profit

firebase update existing db

I created a db at the user registration time, with some empty fields that I want to update once logged in user is at the EditScreen.js
So, inside of that db, I want to target 2 maps with all info/values they have inside.
#1 map "wantsToGetFood" {.......values entered in input fields, and updated on btnpress}
#2 map "wantsToGiveFood" {.......values entered in input fields, and updated on btnpress}
here is a db
In the EditScreen.js
I can check and console log uid like this:
auth.onAuthStateChanged((user) => {
if (user) {
// User logged in already or has just logged in.
console.log('edit screen page look for uid',user.uid);
// } else {
// User not logged in or has just logged out.
// console.log('only for logged in users');
}})
auth comes from my config file "const auth = firebase.auth();"
I cant seem to be able to grab that uid so to go towards map#1 and map#2, so I cant update velues.
Here is what I have so far:
// imports...
export default function EditScreen() {
const[getFoodCheckboxState, getFoodSetCheckboxState] = useState();
const [getFoodText, setGetFoodText] = useState('')
const [importantGetFoodInfo, setImportantGetFoodInfo] = useState('')
const [getFoodAreas, setGetFoodAreas] = useState('')
//and etc... for the rest values
const handleInputChange = () => {
auth
.then((response) => {
const timestamp = firebasestorenotfunc .FieldValue.serverTimestamp()
const dataGetFood = {
ActivityStatusGet: getFoodCheckboxState,
createdAt: timestamp,
getFood: getFoodText,
importantGetFoodInfo: importantGetFoodInfo ,
GetFoodMeetingArea: getFoodAreas,
};
const dataGiveFood = {
ActivityStatusGive: giveFoodCheckboxState ,
createdAt: timestamp,
giveFood: giveFoodText,
importantGiveFoodInfo: importantGiveFoodInfo ,
GiveFoodMeetingArea: giveFoodAreas,
}
const uid = response.user.uid
const usersRef = db.collection('users')
usersRef
.doc(uid)
.child('wantsToGetFood') //map#1
.update(dataGetFood)
.child('wantsToGiveFood') //map#2
.update(dataGiveFood)
.then(() => {
console.log('update was a success');
navigation.navigate('Home')
})
.catch((error) => {
alert(error)
});
})
}
return(......
//TextInputs, text, button, etc...
)}
Current error is: TypeError: undefined is not a function (near '..._config.auth.then...')
how do i fix this, and make an update to the db map values I want?
the closest I got, it can not get uid, it undefined (but console.log if user is logged works and shows uid...

Displaying user data from Firebase Firestore in React Native within a Text tag

Background
Hey! I'm trying to build a header for the home page of my app. I have succesfully implemented email/password auth with Firebase and also persistent credentials. However, I am unable to fetch data from the firestore collection which stores my users.
Basically, what I need is to have my header display "Hello {userName}", but I have absolutely no clue on how to do that.
My Home Screen is a function component, not a class component, so as far as I know I can't go the "componentDidMount()" way.
Question
Which is the best way to fetch the current user's data and display a specific field of information, such as their first name?
How would I go about rendering that within a <Text> tag? Is it something like <Text> Hello {this.user.firstName}</Text> or am I absolutely wrong?
What I've tried
I know this has something to do with this line of code: const usersRef = firebase.firestore().collection('users') but I've no idea what to follow it up with. Also have tried with this method:
var user = firebase.auth().currentUser;
var firstName, email, photoUrl, uid, emailVerified;
if (user != null) {
firstName = user.firstName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid;
}
But that doesn't seem to work. On the last example I'm calling firstName like this: <Text>Hello {firstName}</Text>
You are confusing auth with firestore. Firebase auth only provides credentials and the ability to login and does not enter any data into a database (firestore). What you want to do is when a user is registering you want to set a corresponding document in firestore with the users uid (identification) and all of the users custom data (First name, etc).
Here is an example:
const onRegister = async () => {
try {
const credential = await auth.createUserWithEmailAndPassword(
'email#email.com',
'password',
);
const {uid} = credential;
// your data here (dont forget to store the uid on the document)
const user = {
firstName: 'whatever',
lastName: 'whatever',
user_id: uid,
};
await firestore().collection('users').doc(uid).set(user);
} catch {
//do whatever
}
};
and then when you wanna get their data you can access their document and display it:
const [user, setUser] = useState();
const {uid} = auth().currentUser;
const getUser = async () => {
try {
const documentSnapshot = await firestore()
.collection('users')
.doc(uid)
.get();
const userData = documentSnapshot.data();
setUser(userData);
} catch {
//do whatever
}
};
// Get user on mount
useEffect(() => {
getUser();
}, []);
// return info if user is set
return (
<Text>{user && user?.firstName}</Text>
);

Firebase Cloud Function not executing

I'm working on the group functionality of my app where members of the group can add task to a group that they are currently working on. So, when a task is added I want to notify all members using FCM that a task had been added to the group.
EDIT:
The code to add the task to a group is run on the client and works successfully. The purpose of the cloud function is just to send cloud messages to all the members of the group that a task has been added by a particular member.
This is my logic for the cloud function :
1st. As a task can be added to multiple groups at a time I'm using a forEach().
2nd. I'm fetching the uids of the Members in the groups and pushing them into an array(uids) so that later I can retrieve their fcmTokens.
3rd. Running a forEach on the uids to retrieve the fcmTokens.
4th.Sending Cloud message to devices.
But the cloud function doesn't execute as expected.
This my cloud function:
exports.newTaskAdded = functions.https.onCall(async (data, context) => {
const groups = data.groups; //Can be multiple groups hence an array.
const uid = data.uid;
const author = data.author;
const taskId = data.taskId;
const taskTitle = data.taskTitle;
try {
groups.forEach(async group => {
const groupName = group.groupName;
console.log('groupName: ', groupName);
const groupId = groups.groupId;
const membersPromises = [];
membersPromises.push(
admin
.firestore()
.collection('Groups')
.doc(`${groupId}`)
.collection('Members') //Members collection has document for each user with their uid as the document name.
.get(),
);
console.log('memberPromises: ', membersPromises);//Function stops after this.
const membersSnapshot = await Promise.all(membersPromises);
console.log('membersSnapshots', membersSnapshot);
const uids = [];
membersSnapshot.forEach(doc => {
doc.forEach(snap => {
console.log(snap.id);
uids.push(snap.id);
});
});
console.log(uids);
const uidPromises = [];
uids.forEach(uid => {
uidPromises.push(
admin
.firestore()
.collection('Users')
.doc(`${uid}`)
.get(),
);
});
console.log('uidPromises: ', uidPromises);
const tokensSnapshots = await Promise.all(uidPromises);
const notifPromises = [];
tokensSnapshots.forEach(snap => {
console.log(snap.data());
const token = Object.keys(snap.data().fcmTokens);
const payload = {
notification: {
title: `${author} has added a new task to ${groupName}`,
body: `Task Added: ${taskTitle}`,
sound: 'default',
},
};
notifPromises.push(admin.messaging().sendToDevice(token, payload));
});
await Promise.all(notifPromises);
});
} catch (err) {
console.log(err);
}
return {result: 'OK'};
});
This is my log:
As you can see there is no error shown.
Help would be very much appreciated. Thank you

How to optimize Firestore read/write operation

I try to make Stock monitoring app where users can make Alert when price change.
I have Stock document where I fetch from 3rd party API periodically.
Upon Stock update I fetch all Alert which meet condition and notify users with Firebase messaging.
Here is my models.
/stocks/{stockId}
id: String
price: Number
/alerts/{alertId}
stockId: String
price: Number
condition: [moreThan, lessThan]
uid: String // User who create alert
/users/{userId}
id: String
fcmToken: String
Every 5 minutes I fetch latest stock price and update stock document = number of stock write query.
function updateStockPrice(): Promise<FirebaseFirestore.WriteResult[]> {
const db = admin.firestore();
const options = {
// Options for stock api
};
return client(options)
.then(function(body) {
let batch = db.batch()
for(var stock in body){
let data = // create data from json response
let docRef = db.collection("stocks").doc(//id from 3rd party api)
batch.set(docRef, data)
}
return batch.commit()
});
}
On stock write update, loop through alerts and fetch fcm token from related user to send out push notifications = (alert query + number of alerts matched condition for user query) x number of stock update
export const onStocksUpdate = functions.firestore.document('stocks/{stockId}').onWrite(function(change, context) {
const db = admin.firestore()
const newValue = change.after.data();
const previousValue = change.before.data();
const stockId = Number(context.params.stockId)
let p1 = db.collection("alerts")
.where("stockId", "==", stockId)
.where("condition", "==", "moreThan")
.where("price", "<=", newValue.lastPrice)
.get()
.then(function(querySnapshot) {
const promises = []
querySnapshot.forEach(function(doc) {
let data = doc.data()
let user = db.collection("users").doc(data.uid).get()
user.then(function(snapshot) {
let userData = snapshot.data()
return userData.fcmToken
}).then(function(fcmToken) {
const payload = {
notification: {
title: // title,
body: // body
},
token: fcmToken
}
return admin.messaging().send(payload)
}).catch(function(error) {
console.log(error)
})
promises.push(user)
})
return Promise.all(promises)
}).then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
return p1
})
Total write = number of stock
Total read = (alert query + number of alerts matched condition for user query) x number of stock update
Say I have 20 stocks, 1 user with 3 alerts.
Each 5 minutes I will use 20 write query and (1 + 3) x 20 = 80 read
In 1 day = 5760 write and 23,040 read
This seem too much operations for such a small examples. Is this the right way I should lay out data structure? Or is there a better way to do this?

Resources