I'm new to react native and I'm working on firebase push notification. I'm getting the notification, but the problem is I'm not able to fetch data and display it in flatlist. Notification are shown perfectly. But the problem is why I can't fetch data. I want this event data to be fteched in my notification list which i have added below image.
componentWillMount() {
const firebase = require("firebase");
if (!firebase.apps.length) {
firebase.initializeApp(db);
}
this.fetchEventsList()
}
// Fetch events list
fetchEventsList = () => {
Preference.set('userPhoneCheck', '+917508060520');
let phone = Preference.get('userPhoneCheck');
firebase.database().ref('/users').child(phone).child('/events').once('value').then((snapshot) => {
let data = snapshot.val();
let items = Object.values(data);
this.setState({
userEventsList: items
});
// this.deleteOldEvents();
this.initAllEventList();
}).then((data) => {}).catch((error) => {
//error callback
console.log('error ', error)
})
}
//fetch the friends list according to group name
initAllEventList = () => {
//let groupName='G1';
let eventId = '';
let userEventsList = [...this.state.userEventsList];
for (var i = 0; i < userEventsList.length; i++) {
eventId = userEventsList[i].eventId;
ToastAndroid.show("eventId>" + eventId, ToastAndroid.SHORT);
if (eventId != '') {
this.fetchFriendsList(eventId);
}
}
}
//app users remove that not in contacts
fetchFriendsList = (eventId) => {
let allEventsList = [...this.state.allEventsList];
firebase.database().ref('/events').child(eventId).once('value').then((snapshot) => {
let data = snapshot.val();
let items = Object.values(data);
allEventsList.push(items);
this.setState({
allEventsList: allEventsList
});
ToastAndroid.show("kk>" + allEventsList.length, ToastAndroid.SHORT);
}).then((data) => {
}).catch((error) => {
//error callback
console.log('error ', error)
})
}
Related
I'm using Firestore to store messages. In order to optimize the mobile application performances, I would like to set a limit(50) in the firestore query.
It works well and implemented the onLoadEarlier React-native-gifted-chat available in the props.
All is working fine.
But, when I send a new message in the chat, after scrolled up to see the earliers messages, only the 50 last messages with the new one, off course, are available.
So, each time I'm adding a message in the Firestore database, the onSnapshot (in the useeffect) is executed and apply the limit query.
Is there a way to avoid this ?
Thanks.
Here my useEffect :
useEffect(() => {
const messagesListener = firestore()
.collection('groups')
.doc(group._id)
.collection('messages')
.orderBy('createdAt', 'desc')
.limit(50)
.onSnapshot(querySnapshot => {
const newMessages = querySnapshot.docs.map(doc => {
const firebaseData = doc.data();
const data = {
_id: doc.id,
text: '',
createdAt: new Date().getTime(),
...firebaseData
};
return data;
});
setMessages(previousMessages => {
return GiftedChat.append(previousMessages, newMessages);
});
});
return () => messagesListener();
}, []);
I am using FlatList in react-native to render chats and I had to paginate the chats list. Since Firestore query cursor is not supported in live listener, I created two list, recentChats & oldChats.
I populate recentChats using live listener query.onSnapshot & oldChats using cursor startAfter. FlatList data is combination of both list and I take care of merging logic.
const MESSAGE_LIMIT = 15;
const ChatWindow = props => {
const { sessionId, postMessage, onSendTemplateButtonPress } = props;
// Firestore cursor is not supported in query.onSnapshot so maintaining two chat list
// oldChats -> chat list via cursor, recentChats -> chat list via live listener
const [oldChats, setOldChats] = useState([]);
const [recentChats, setRecentChats] = useState([]);
// if true, show a loader at the top of chat list
const [moreChatsAvailable, setMoreChatsAvailable] = useState(true);
const [inputMessage, setInputMessage] = useState('');
useEffect(() => {
const query = getGuestChatMessagesQuery(sessionId)
.limit(MESSAGE_LIMIT);
const listener = query.onSnapshot(querySnapshot => {
let chats = [];
querySnapshot.forEach(snapshot => {
chats.push(snapshot.data());
});
// merge recentChats & chats
if (recentChats.length > 0) {
const newRecentChats = [];
for (let i = 0; i < chats.length; i++) {
if (chats[i].sessionId === recentChats[0].sessionId) {
break;
}
newRecentChats.push(chats[i]);
}
setRecentChats([...newRecentChats, ...recentChats]);
} else {
setRecentChats(chats);
if (chats.length < MESSAGE_LIMIT) {
setMoreChatsAvailable(false);
}
}
});
return () => {
// unsubscribe listener
listener();
};
}, []);
const onMessageInputChange = text => {
setInputMessage(text);
};
const onMessageSubmit = () => {
postMessage(inputMessage);
setInputMessage('');
};
const renderFlatListItem = ({ item }) => {
return (<ChatBubble chat={item} />);
};
const onChatListEndReached = () => {
if (!moreChatsAvailable) {
return;
}
let startAfterTime;
if (oldChats.length > 0) {
startAfterTime = oldChats[oldChats.length - 1].time;
} else if (recentChats.length > 0) {
startAfterTime = recentChats[recentChats.length - 1].time;
} else {
setMoreChatsAvailable(false);
return;
}
// query data using cursor
getGuestChatMessagesQuery(sessionId)
.startAfter(startAfterTime)
.limit(MESSAGE_LIMIT)
.get()
.then(querySnapshot => {
let chats = [];
querySnapshot.forEach(snapshot => {
chats.push(snapshot.data());
});
if (chats.length === 0) {
setMoreChatsAvailable(false);
} else {
setOldChats([...oldChats, ...chats]);
}
});
};
return (
<View style={[GenericStyles.fill, GenericStyles.p16]}>
<FlatList
inverted
data={[...recentChats, ...oldChats]}
renderItem={renderFlatListItem}
keyExtractor={item => item.messageId}
onEndReached={onChatListEndReached}
onEndReachedThreshold={0.2}
ListFooterComponent={moreChatsAvailable ? <ActivityIndicator /> : null}
/>
{
Singleton.isStaff ?
null:
<ChatInput
onMessageInputChange={onMessageInputChange}
onMessageSubmit={onMessageSubmit}
inputMessage={inputMessage}
style={GenericStyles.selfEnd}
onSendTemplateButtonPress={onSendTemplateButtonPress}
/>
}
</View>
);
};
Your query is OK for the first time, for consequent queries you must use the ::startAt or ::startAfter methods.
You can find more information in the official documentation.
https://firebase.google.com/docs/firestore/query-data/query-cursors
I need to concatenate two objects in Vue/Javascript and order the resulting one by date field but I'm getting empty results using Object.assign().
I've tried other methods searching on StackOverflow but nothing has worked as expected. Mostly I get empty results
methods: {
getAllMessages: function () {
// console.log(this.myID);
let distinct = '';
firebase.firestore().collection('private-messages').where('memberID', '==', `${this.myID}`)
.orderBy('date').onSnapshot(res => {
let members = [];
res.forEach(doc => {
members.push(doc.data().uid);
});
distinct = Array.from(new Set(members));
// console.log(distinct);
this.getUserToTalk(distinct);
});
},
getMyMessages: function (memberID) {
let myMessages = [];
firebase.firestore().collection('private-messages').where('uid', '==', `${this.myID}`).where('memberID', '==', `${memberID}`)
.orderBy('date').onSnapshot(res => {
res.forEach(doc => {
myMessages.push(doc.data());
});
});
// this.myMessages = myMessages;
return myMessages;
},
getMessages: function (memberID) {
let messages = [];
firebase.firestore().collection('private-messages').where('uid', '==', `${memberID}`).where('memberID', '==', `${this.myID}`)
.orderBy('date').onSnapshot(res => {
res.forEach(doc => {
messages.push(doc.data());
});
});
// this.memberMessages = messages;
return messages;
},
getUserToTalk: function (memberID) {
axios.post('http://localhost/backend/getMemberToTalk.php', {
"token": token,
"whoToTalkTo": memberID,
}).then(response => {
if (response.data != "Error getting user data and tour") {
let joinedData = []
// console.log(response.data);
response.data.forEach(res => {
let id = res.memberID;
let messages = this.getMessages(id);
// console.log(messages);
let myMessages = this.getMyMessages(id);
// console.log(myMessages);
// if I use below assignment I can get the messages, but I need to concat them.
// so, if I use let conversation = Object.assign({}, messages, myMessages);
// or let conversation = { ...messages, ...myMessages }
// the result is always empty.
let talk1 = Object.assign(messages);
let talk2 = Object.assign(myMessages);
console.log(talk, talkmy);
let data = {
memberID: res.memberID,
memberProfileImg: res.memberProfileImg,
memberName: res.memberName,
memberLastname: res.memberLastname,
memberCity: res.memberCity,
memberState: res.memberState,
memberMessages: messages,
myMessages: myMessages,
// messages: conversation
}
joinedData.push(data);
});
// console.log(joinedData);
this.memberData = joinedData;
// console.log(this.memberData);
} else {
console.log(response.data);
}
}).catch(error => {
console.log(error);
});
},
}
These are the full objects and in the example below I need to add the object from messages.js:140 as a "third index" in messages.js:137 resulting in
0:{...}
1:{...}
2:{...}
and then
3:{...}
I'm trying to grab some data(title, last name, first name and also large photo of the user profile returned by the API.) from the API https://randomuser.me/api/, which seem to not be working.
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
let {results} = data;
let [profile] = results;
document.querySelector('h2').textContent = profile.name.title +' '+ profile.name.last +' '+ profile.name.first;
document.querySelector('img').src = profile.picture.large;
displayExtraUserInfo(profile);
clearNotice();
};
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
fetch(api)
.then((resp) => resp.json())
.then(data => {displayUserPhotoAndName()});
notify(`requesting profile data ...`);
};
const displayBirthdate = ({dob = 'dob'}) => {
document.querySelector('.details').textContent = dob.age;
}
const displayPhone = ({phone = 'phone', cell = 'cell'}) => {
document.querySelector('.details').textContent = phone + ', ' + cell;
}
const displayAddress = ({location = 'location'}) => {
document.querySelector('.details').textContent = location.street + ', ' + location.city + ', ' + location.state;
}
You are passing the data to the function.Do like below
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
fetch(api)
.then((resp) => resp.json())
.then(data => {displayUserPhotoAndName(data)}); //this line is changed
notify(`requesting profile data ...`);
};
Here is the line that will get all the required properties
let {results:[{ name: { title , first , last } , picture:{ large } }]} = data;
Here is how you can do it and also handle bad data with default values. Also, do not forget to pass data to your function in the then callback:
const display = data => {
const { results: [{ name: { title, first, last } = {}, picture: { large } = {} }] = [] } = data || {};
console.log(title, first, last, large);
};
fetch('https://randomuser.me/api/').then(r => display(r.json()));
I wrote this to detect a docment change,when it changes i want to send notifications to all the users who all are inside the Collection "users"
the problem is How to choose all docments inside a collection??
/*eslint-disable */
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification23 = functions.firestore.document("student/anbu").onWrite(event => {
//now i'm returning to my personal document and fetched my username only because i don't want to send a notification to myself,
const fromUser = admin.firestore().collection("users").doc("iamrajesh#gmail.com").get();
//here i want to fetch all documents in the "users" collection
const toUser = admin.firestore().collection("users").document.get();//if i replace "docmument" with "doc("xxxxxxx#gmail.com")" it works it fetches his FCM but how to fetch all documents??
//All documents has a "username",and a fcm "token"
return Promise.all([fromUser, toUser]).then(result => {
const fromUserName = result[0].data().userName;
const toUserName = result[1].data().userName;
const tokenId = result[1].data().tokenId;
const notificationContent = {
notification: {
title: fromUserName + " is shopping",
body: toUserName,
icon: "default",
sound : "default"
}
};
return admin.messaging().sendToDevice(tokenId, notificationContent).then(result => {
console.log("Notification sent!");
//admin.firestore().collection("notifications").doc(userEmail).collection("userNotifications").doc(notificationId).delete();
});
});
});
The following should do the trick.
See the explanations within the code
/*eslint-disable */
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification23 = functions.firestore.document("student/anbu").onWrite((change, context) => {
// Note the syntax has change to Cloud Function v1.+ version (see https://firebase.google.com/docs/functions/beta-v1-diff?0#cloud-firestore)
const promises = [];
let fromUserName = "";
let fromUserId = "";
return admin.firestore().collection("users").doc("iamrajesh#gmail.com").get()
.then(doc => {
if (doc.exists) {
console.log("Document data:", doc.data());
fromUserName = doc.data().userName;
fromUserId = doc.id;
return admin.firestore().collection("users").get();
} else {
throw new Error("No sender document!");
//the error is goinf to be catched by the catch method at the end of the promise chaining
}
})
.then(querySnapshot => {
querySnapshot.forEach(function(doc) {
if (doc.id != fromUserId) { //Here we avoid sending a notification to yourself
const toUserName = doc.data().userName;
const tokenId = doc.data().tokenId;
const notificationContent = {
notification: {
title: fromUserName + " is shopping",
body: toUserName,
icon: "default",
sound : "default"
}
};
promises.push(admin.messaging().sendToDevice(tokenId, notificationContent));
}
});
return Promise.all(promises);
})
.then(results => {
console.log("All notifications sent!");
return true;
})
.catch(error => {
console.log(error);
return false;
});
});
I'm making an iOS app and I have this problem now.
I'd like to count the number of unread messages in database and assign it in a database different closure. Like below.
exports.arrivalNotifications = functions.database.ref('/trips/{tripId}')
.onCreate((snap, context) => {
const data = snap.val();
const uid = data.uid;
var counter = 0
admin.database().ref('/messages/').on('value', function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var childData = childSnapshot.val();
if (childData.read === false) {
counter += 1
}
});
})
return admin.database().ref('/users/' + uid).once('value', snapshot => {
const data = snapshot.val();
const username = data.username
var payload = {
notification: {
title: username ' has ' + counter + " unread message.",
body: 'Press for more'
}
}
admin.messaging().sendToDevice(toUser.fcmToken, payload)
.then(function(response) {
console.log("Successfully sent message:", response);
return null;
})
.catch(function(error) {
console.log("Error sending message:", error);
});
})
})
So I want to use the counter in the payload but I can't find the way to do it. I'm not familiar with JavaScript so if someone can help me I'd appreciate.
I would write your Cloud Function as follow. Please note that I could not test it and it may need some fine-tuning/debugging... especially since it implies chaining several promises.
exports.arrivalNotifications = functions.database.ref('/trips/{tripId}').onCreate((snap, context) => {
const data = snap.val();
const uid = data.uid;
let counter = 0;
return admin.database().ref('/messages/').once('value')
.then(snapshot => {
snapshot.forEach(function (childSnapshot) {
const childData = childSnapshot.val();
if (childData.read === false) {
counter += 1;
}
});
return admin.database().ref('/users/' + uid).once('value');
})
.then(snapshot => {
const data = snapshot.val();
const username = data.username;
const payload = {
notification: {
title: username + ' has ' + counter + ' unread message.',
body: 'Press for more'
}
};
return admin.messaging().sendToDevice(toUser.fcmToken, payload);
})
.then(response => {
console.log("Successfully sent message:", response);
return null;
})
.catch(error => {
console.log("Error sending message:", error);
});
});