messaging().onNotificationOpenedApp calling multiple times - firebase

when i click on a notification , messaging().onNotificationOpenedApp function calling multiple times
useEffect(() => {
messaging().onNotificationOpenedApp(async remoteMessage => {
if (remoteMessage) {
const notification =
JSON.parse(String(remoteMessage.data));
const notificationData = NotificationMapper([notification]);
await notificationNavigation(notificationData[0]);
}
})}, []);
this is my code ,please help me out to prevent calling above function multiple times

Related

dispatch is not a function Next.js +thunk load data user after login

When I'm try to getUserProfile() I receive that typeError that dispatch is not a function
Unhandled Runtime Error
Error: Actions must be plain objects. Use custom middleware for async actions.
export const fetchUserProfile = (userData) => ({
type: types.GET_USER_PROFILE,
userData,
});
//thunk
export const loginUser = (credentials) => async (dispatch) => {
dispatch(loginRequest(credentials));
try {
const userToken = await userService.login(credentials);
await dispatch(loginSuccess(userToken));
getUserProfile();
} catch (error) {
const message = await errorMessage(
error,
"There was a problem processing your request"
);
dispatch(loginFailure(message));
}
};
export const getUserProfile = async (dispatch) => {
try {
const profileData = await userService.getProfileData();
dispatch(fetchUserProfile(profileData));
} catch (e) {
console.log(e);
return [];
}
};
You need to dispatch all thunks, replace
getUserProfile();
with
dispatch(getUserProfile())
Your getUserProfile should be a function that accepts its own arguments when you dispatch it, and then it can either be a callback function that accepts dispatch as an argument (this comes from the Redux Thunk middleware) and then that function has functions that return action objects, OR it can just be a function that returns an action object directly (confusing, I know, but you actually did it correctly for your loginUser action):
export const getUserProfile = () => async (dispatch) => {
try {
const profileData = await userService.getProfileData();
dispatch(fetchUserProfile(profileData));
} catch (e) {
console.log(e);
return []; // this shouldn’t be returning an empty array, if anything it should be dispatching an action for errors that can be displayed to the user
}
};
This overly simple example kind of gives you an idea of what's happening (click Run code snippet):
// the "dispatch" function that would come from
// the Redux Thunk middleware
const dispatch = (action) => action((args) => console.log("dispatch:", JSON.stringify(args, null, 2)));
// a "setUserProfile" action that returns an object
const setUserProfile = (payload) => ({
type: "SET_PROFILE",
payload
});
// a "fetchUserProfile" action that returns an object
const fetchUserProfile = () => ({ type: "FETCH_USER" });
// a "showError" action that returns an object
const showError = error => ({ type: "FETCH_USER/ERROR", payload: error });
// while the "getUserProfile" action doesn't have any arguments of
// its own, it accepts a "dispatch" callback function as the SECOND
// set of arguments, then other actions are dispatched (which return
// their own objects)
const getUserProfile = () => async(dispatch) => {
try {
// dispatches the "fetchUserProfile" action
// which just returns: { type: "FETCH_USER" }
dispatch(fetchUserProfile());
// fetching data from API
const res = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data = await res.json();
// dispatches the "setUserProfile" with data from API
// which returns: { type: "SET_PROFILE", payload: data }
dispatch(setUserProfile(data));
} catch (e) {
console.log(e);
dispatch(showError(e.message));
}
};
// dispatching the "getUserProfile" function above
// optionally, you can add arguments here, but then these would be
// a part of the FIRST set of arguments to the function
dispatch(getUserProfile());
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>

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 subscribe a firebase function so that it executes via a pub/sub trigger

I have been asked to create a firebase (fb) function that triggers onUpdate. Then I have to gather a bunch of information from the fb database and publish a message so that another function triggers at that point.
fb update triggers functionA
functionA publishes a message
functionB is a subscriber to that topic and is triggered after the message publishes.
I have the basics of the onUpdate trigger below:
const functions = require("firebase-functions"),
Promise = require("promise"),
PubSub = require(`#google-cloud/pubsub`),
admin = require("firebase-admin");
const pubsub = new PubSub();
exports.checkInOrder = functions.database
.ref("/orders/{id}")
.onUpdate((change, context) => {
const after = change.after.val();
// check the status: "pending-pickup" or "fulfilled" TODO
if (after.status === "new") {
console.log("ended because package is new.");
return null;
}
let dsObj = {};
const orderId = context.params.id;
const topicName = 'check-in-order';
const subscriptionName = 'check-in-order';
return // how would I send the message to the pubsub here?
});
So to summarize:
How do I send a message to pubsub
How do I subscribe a firebase function to trigger when a topic receives a message?
If it sounds very confusing I'm sorry - I am completely lost here. Thanks!
So I finally figured it out. Pretty straight forward, just felt overwhelmed with learning all of this stuff at once and in a rushed time frame. Below is my code. I included the whole page so in case this might help someone else out there in the future.
const functions = require("firebase-functions"),
Promise = require("promise"),
PubSub = require(`#google-cloud/pubsub`),
admin = require("firebase-admin");
const init = () => {
const topicName = "check-in-order";
pubsub
.createTopic(topicName)
.then(results => {
const topic = results[0];
console.log(`Topic ${topicName} created.`);
return;
})
.catch(err => {
console.error("ERROR on init:", err);
return;
});
};
const pubsub = new PubSub();
exports.orderCreated = functions.database
.ref("/orders/{id}")
.onUpdate((change, context) => {
console.log("it's happening!");
const after = change.after.val();
console.log("after::::>", after)
if (after.status === "new") {
console.log('stopped because status is new');
return null;
}
if (after.status === "pending-pickup" || after.status === "fulfilled") {
const orderId = context.params.id;
const topicName = "check-in-order";
let { assignedSlot, userId, parcelLockerId, carrier, trackingNumber, orderInDate, pickUpCode, status, } = after;
const dsObj = {
order: {
orderId,
userId,
parcelLockerId,
carrier,
trackingNumber,
orderInDate,
pickUpCode,
status,
}
};
const dataBuffer = new Buffer.from(dsObj.toString());
// publish to trigger check in function
return pubsub
.topic(topicName)
.publisher()
.publish(dataBuffer)
.then(messageId => {
console.log(`:::::::: Message ${messageId} has now published. :::::::::::`);
return true;
})
.catch(err => {
console.error("ERROR:", err);
throw err;
});
}
return false;
});
exports.checkInOrder = () => {
}
exports.checkIn = functions.pubsub.topic('check-in-order').onPublish((message) => {
console.log("everything is running now", message);
return true;
});
init();

Firebase Deploy Error: Failed to configure trigger

I have following sample function from this tutorial: Asynchronous Programming (I Promise!) with Cloud Functions for Firebase - Firecasts
exports.emailEmployeeReport = functions.database
.ref('/employees/${eid}/reports/${rid}')
.onWrite(event => {
const eid = event.params.eid;
const report = event.data.val().report;
const root = event.data.ref.root;
const mgr_promise = root.child(`/employees/${eid}/manager`).once('value');
const then_promise = mgr_promise.then(snap => {
const mgr_id = snap.val();
const email_promise = root.child(`/employees/${mgr_id}/email`).once('value');
return email_promise;
}).catch(reason => {
// Handle the error
console.log(reason);
});;
const then_promise2 = then_promise.then(snap => {
const email = snap.val();
const emailReportPromise = sendReportEmail(email, report);
return emailReportPromise;
}).catch(reason => {
// Handle the error
console.log(reason);
});
return then_promise2;
});
var sendReportEmail = function (email, report) {
const myFirstPromise = new Promise((resolve, reject) => {
// do something asynchronous which eventually calls either:
//
setTimeout(function () {
try {
var someValue = "sendReportEmail";
console.log(someValue);
// fulfilled
resolve(someValue);
}
catch (ex) {
// rejected
reject(ex);
}
}, 2000);
});
return myFirstPromise;
}
once I run firebase deploy command, eventually I am getting following error:
functions[emailEmployeeReport]: Deploy Error: Failed to configure
trigger
providers/google.firebase.database/eventTypes/ref.write#firebaseio.com
(emailEmployeeReport)
I also have a simple hello-world method and a similar trigger method, and they deploy fine.
Am I missing something here?
The syntax for wildcards in the database reference does not have "$".
Try the following:
exports.emailEmployeeReport = functions.database
.ref('/employees/{eid}/reports/{rid}')

Cloud Function keeps running

We have a Firebase function which removes items after 24 hours. The function works, however, the web page linking to the function keeps running so I guess the function is in an endless loop. Is there any way to fix this issue?
This is our function:
exports.delete = functions.https.onRequest((req, res) => {
const currentTime = new Date().getTime();
const dayAgo = currentTime - 86400000;
ref.child('testlijst')
.orderByChild('tijd')
.endAt(dayAgo)
.once('value')
.then(snap => {
snap.forEach(c => {
c.ref.remove();
})
});
});
You are required to send a response to the client in order to terminate an HTTPS type function without timing out. You should do that only after the work you're doing in the function is complete. This means you'll need to learn how to use promises.
You will need to collect all the promises returned by c.ref.remove() and wait for all of them to complete before terminating the function with a response to the client:
ref.child('testlijst')
.orderByChild('tijd')
.endAt(dayAgo)
.once('value')
.then(snap => {
const promises = [];
snap.forEach(c => {
const p = c.ref.remove();
promises.push(p);
})
Promise.all(promises).then(result => {
res.send("done");
});
});
});

Resources