How to create Firebase push notifications group in React Native? - firebase

I get a problem using Firebase to create push notifications group in React Native, when I receive many push notifications I want to create it to be 1 group like WhatsApp (like red circle in image below).
I have tried to look for many examples but I didn't found a solution. Please anyone help me to create like that.
Thanks.

use react-native-push-notification
// create channel
import PushNotification, {Importance} from 'react-native-push-notification';
...
PushNotification.createChannel(
{
channelId: "channel-id", // (required)
channelName: "My channel", // (required)
channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
playSound: false, // (optional) default: true
soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration pattern if true.
},
(created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
);
// this shows each new notification for a while then pushes it into group
PushNotification.localNotification({
channelId: 'channel-id',
title: `New message`,
message: 'Hello world',
})
// this groups messages
PushNotification.localNotification({
channelId: 'channel-id',
id: 'messages',
group: 'messages',
groupSummary: true
})

Related

Convert PushNotification.localNotification to firebase push notification

I am working on a school thesis with the concept of Geofence. For my project, i have made notifications to arrive based on the boundary events. The project works with local notifications coming based on events:
Boundary.on(Events.ENTER, id => {
console.log('Background Enter');
PushNotification.localNotification({
channelId: 'boundary-demo',
title: 'ENTER SIGNAL',
message: `You've entered region: ${id} in background`,
importance: 'max',
priority: 'max',
ignoreInForeground: false,
allowWhileIdle: true,
});
});
Boundary.on(Events.EXIT, id => {
console.log('Background Exit');
PushNotification.localNotification({
channelId: 'boundary-demo',
title: 'EXIT SIGNAL',
message: `You've left region: ${id} in background`,
importance: 'max',
priority: 'max',
ignoreInForeground: false,
allowWhileIdle: true,
});
});
I am making a single app, which 2 users can login and use (Parent and child)
Right now, because it is using localnotification, One device can recieve the notification. But i need the same notifications to come at both devices.
So how do I convert PushNotification.localNotification to Firebase Push Notification.
NOTE: Both users have been linked together with firebase realtime database.
Please help, thank you so much

Permissions in Firebase notifications

I have created this function in Google Cloud Platform associated with Firebase Realtime Database. The function sends a notification to mobile applications when something appears in the database.
As you can see below I set the priorities so that the notification will be noticed by the user
var message = {
token: tokenSnapshot,
notification: {
title: "Title",
body: "Body",
},
android: {
priority: 'high',
notification: {
sound: 'default',
priority: 'high',
visibility: 'public'
}
},
};
Unfortunately, it doesn't do anything. The notification comes but the user sees when he checks manually if something has come
I use a standard approach in the application
messaging().enable.setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', JSON.stringify(remoteMessage));
})
Is there any way for notifications to be with sound, vibration and to appear on the lock screen?
I haven't used the react-native-push-notification library yet. Can this library help in this?
If you are using firebase-cloud messaging i suggest using firebase in your app.
https://rnfirebase.io/messaging/usage
Make sure you follow the initial set up first.
Please read more about this here. https://rnfirebase.io/

How to use Sign-In User ID to send push notifications

I have some users signed into my actions-on-google app via Google Sign-In ( https://developers.google.com/actions/identity/google-sign-in )
I want to sent push notifications to one of those users.
For getting push notifications work with actions in the first place, I tried this sample: https://github.com/actions-on-google/dialogflow-updates-nodejs/blob/master/functions/index.js but I only can get this to work without this commit: https://github.com/actions-on-google/dialogflow-updates-nodejs/commit/c655062047b49e372da37af32376bd06d837fc7f#diff-1e53ef2f51bd446c876676ba83d7c888
It works fine, but I think const userID = conv.user.id; returns the deprecated Anonymous User ID. The commit suggests to use const userID = conv.arguments.get('UPDATES_USER_ID'); which returns undefined.
I use this nodejs code to send the push notifications.
const request = require('request');
const {JWT} = require('google-auth-library');
const serviceAccount = require('./service-account.json');
let jwtClient = new JWT(
serviceAccount.client_email, null, serviceAccount.private_key,
['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
null
);
jwtClient.authorize((authErr, tokens) => {
let notification = {
userNotification: {
title: process.argv[2],
},
target: {
userId: USERID,
intent: 'tell_latest_status',
// Expects a IETF BCP-47 language code (i.e. en-US)
locale: 'en-US'
},
};
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token,
},
'json': true,
'body': {
'customPushMessage': notification, 'isInSandbox': true
},
}, (reqErr, httpResponse, body) => {
console.log(httpResponse.statusCode + ': ' + httpResponse.statusMessage);
});
});
I simply can't get this to work with the const userID = conv.arguments.get('UPDATES_USER_ID'); version, because as I said
When I use conv.user.profile.payload.sub as suggested here: https://developers.google.com/actions/identity/user-info the AoG API returns "SendToConversation response: Invalid user id for target."
Is there any way to make this work with Google Sign-In?
Has anyone made this work? I mean with the UPDATES_USER_ID field?
I already created an issue on the samples repo: https://github.com/actions-on-google/dialogflow-updates-nodejs/issues/15 but I was sent here.
Thanks!
While researching why I sometimes got undefined I found an answer on this question that solved my issue.
I've found solution for this problem. While getting UPDATES_USER_ID
conv.arguments.get() only works for first attempt. So, while building
your action you must save it. If you didn't store or save, you can
reset your profile and try again, you will be able to get.
You can reset your user profile for the action here.

Error trying to test tokenized payments

CONTEXT
I'm writing a custom checkout process using tokenized payments inside a WebView since I need to use payments outside US.
I'm using this code, based on this facebook guide, to ask for the user's credit card info.
const saveThis = this
MessengerExtensions.requestPaymentCredentials(
function success(name, email, cardType, cardLastFourDigits, shippingAddress) {
console.log('success getting user payment info', cardLastFourDigits)
saveThis.printAsyncData(cardType)
},
function error(err, errorMessage) {
console.log('error trying to get user payment info', errorMessage)
saveThis.printAsyncData(errorMessage)
},
['CONTACT_NAME', 'CONTACT_EMAIL', 'CONTACT_PHONE', 'SHIPPING_ADDRESS']
);
CONSIDERATIONS
saveThis.printAsyncData() function is a workaround to log the
output in mobile devices so I can debug the code, since payments
don't work using the Messenger web client.
I'm testing this chatbot with my facebook account which is the one having the chatbot's Administrator role.
Administrator user returns the profile property is_payment_enabled: true
OUTPUT
I'm getting the following error: "An unexpected error has occured.24002". In the facebook's error reference, 24002 means "Payment request cannot be processed due to missing privacy url".
QUESTION
Does that mean that I have to provide a privacy policy URL to test payments even when I'm using the Administrator's chatbot account in a testing environment??
UPDATE
As suggested, I implemented the updated WebView payment code as follows:
const methodData = [{
supportedMethods: ['fb'], //only 'fb' is supported
data: {
merchantTitle: 'Merchant name', // optional, defaults to the Facebook Page name
merchantImageUrl: 'imageURL', //optional, defaults to the app icon
confirmationText: 'Thank you!', // optional, defaults to "Thank you for your payment"
merchantFBPageId: '28636603843****', // page id with onboarded payment method. Need to be the same with the page id in thread or messenger extension
termsUrl: 'https://www.facebook.com/' // Merchant payment privacy terms and conditions.
}
}]
const paymentDetails = {
displayItems: [ //array of items being charged for
{
label: 'T-shirt',
amount: {
currency: 'USD',
value : '15.00'
}
}
],
total: {
label: 'Total', // defaults to "Total"
amount: {
currency: 'USD',
value : '16.23'
}
},
shippingOptions: [ // Optional. Array of options for user to select
{
id: 'free-shipping', // custom ID
label: 'Free shipping in US', //human-readable name
amount: {currency: 'USD', value: '0.00'},
selected: true
}
]
}
const additionalOptions = {
requestShipping: false, // If shipping is required. If true, handle shippingoptionchange and shippingaddresschange events.
requestPayerName: true, // Name of the payer sent with the final response
requestPayerEmail: true, // Email address, same as above
requestPayerPhone: false // Phone number, same as above
}
let request = new this.messengerExtensions.PaymentRequest(
methodData, // array of payment methods and their setup
paymentDetails, // array of items, total, shipping options
additionalOptions, // request shipping information, payee email address, etc
);
request.canMakePayment()
.then(response => {
this.printAsyncData(response + ' from canMakePayment')
if (response === true) {
// proceed
} else {
// something went wrong, e.g. invalid `displayItems` configuration
// or the device does not run a
// recent enough version of the Facebook app
}
})
.catch(error => {
this.printAsyncData(error+' error from canMakePayment')
// an error such as `InvalidStateError`
// if a payment is already in process
});
This suggested implementation returns the variable response as false. Each configuration variable is copied from this link. I changed the MerchantPageID with the PageID I found on my Chatbot's fb page > Information, so I don't think this could be the problem. I checked the Messenger's version of my Android device and is the latest, being the 147.0.0.25.86 one.
I even tried to implement the payment dialog as follows just to see how it behaves.
request.show().then(response => {
// Process the payment if using tokenized payments.
// Process the confirmation if using Stripe/PayPal
this.printAsyncData(response)
// paymentResponse.complete('success').then(() => {
// // cleanup UI, log, etc
// });
}).catch(error => this.printAsyncData(error+'from show()'));
Payment dialog pops over nicely. It shows user's name and email but under the METHOD PAYMENT header it shows a loading spinner indefinitely. Moreover, .show() never triggers the callback thus not allowing to print its response on the line before paymentResponse.complete('success').
UPDATE 2
I've got the supported features with the following code to try to get some clue of what I'm missing
const saveThis = this
MessengerExtensions.getSupportedFeatures(function success(result) {
var features = result.supported_features;
saveThis.printAsyncData(features)
}, function error(err, errorMessage) {
saveThis.printAsyncData(errorMessage)
});
This is the output on my android messenger client:
["sharing_broadcast","sharing_direct", "sharing_open_graph", "permissions", "thread_context", "context", "sharing_media_template"]
There is no "payments" as it should be, based on this reference
Yes, but since you are just testing it can be any URL. Once you submit your bot for approval it will need to point to a real privacy policy.
You are also using the deprecated version of payments. For webview payments you should use PaymentRequest which is explained here:
https://developers.facebook.com/docs/messenger-platform/payments/webview-payments

Adding more fields to Meteor user accounts

I am using mrt add accounts-ui-bootstrap-dropdown and mrt add accounts-password to get a simple login page running on my app.
The accounts users gives me a nice hash containing ids, createdAt, emails, etc.
If I wanted to add other fields in this hash so I can make use of them later, how would I do that? For example, I want then to also enter their given name and surname:
"given_name": "John", "surname": "Doe"
Users are special objects in meteor ; you don't want to add fields in the user but in the users profile.
From the doc :
By default the server publishes username, emails, and profile.
If you want to add properties like surname when you create the account, you should use in the Account.onCreateUser server-side hook : http://docs.meteor.com/#accounts_oncreateuser
Accounts.onCreateUser(function(options, user) {
//pass the surname in the options
user.profile['surname'] = options.surname
return user
}
If you want to update a user after, you can do it from the client that way :
Meteor.users.update({_id:Meteor.user()._id}, { $set: {what you want to update} });
By default, the users base will allow that (the current user may update itself). If you don't trust your users and want to ensure that everything is properly update, you can also forbid any updates from the client and make them via a Meteor.call() and proceed to the checkings server-side. But this would be sad.
Edit :
As said in the comments, adding options via the standard account-ui won't be possible. You'll only be able to update the user after the registration. To add options when you subscribe, you'll have to make you own form.
I won't insult you by writing html markup, but here is what you want to have after the submit event (and after the various checking) :
var options = {
username: $('input#username')[0].value,
emails: [{
address: $('input#email')[0].value,
verified: false
}],
password: $('input#password')[0].value,
profile: {
surname: $('input#surname')
},
};
Accounts.createUser( options , function(err){
if( err ) $('div#errors').html( err.message );
});
You only need the account-base package ; not the account-ui.
Login with the social networks is cake :
Meteor.loginWithFacebook({
requestPermissions: ['email', 'user_birthday', 'user_location']
}, function(error){loginCallBack(error);});
About the answer ram1 made :
This is not the way meteor works. You do not "POST" a form. You want all your client / server communication done via the websocket. The equivalent of what you are talking about is making a "Meteor.call('myserverfunction', myarguments, mycallback)" of a server method from the client and you pass the arguments you want the server to use.
But this is not the way you will get the best of meteor. There is the philosophy you want to work with :
you have datas in your local mini mongo you got from the server
you update locally those datas in your base / view
meteor do his magic to transmit those updates to the server
there the server can answer : ok, updates saved, this is seamless for you. Or answer : nop ! reverse the changes (and you can implement an error notification system)
(it can answer no because you don't have the permission to update this field, because this update break a rule you did set up...)
All you do is setting permissions and controls on the databases server-side. That way, when an honest client make an update, he sees the result instantly ; way before it has been pushed to the server and send to the other clients. This is latency compensation, one of the seven principles of meteor.
If you modify a data via Meteor.call, you will do that :
send an update to the server
the server checks and update the base
the server send the update to the clients (including you)
your local base updates and your view update => you see your update
=> this is what you had in yesterday app ; meteor allow you to build a today app. Don't apply the old recipes :)
The accepted answer has the HOW right, but the WHERE is outdated information. (Yes, this would be better as a comment on the answer, but I can't do that yet.)
From the Meteor 1.2 documentation:
The best way to store your custom data onto the Meteor.users collection is to add a new uniquely-named top-level field on the user document.
And regarding using Meteor.user.profile to store custom information:
🔗Don’t use profile
There’s a tempting existing field called profile that is added by
default when a new user registers. This field was historically
intended to be used as a scratch pad for user-specific data - maybe
their image avatar, name, intro text, etc. Because of this, the
profile field on every user is automatically writeable by that user
from the client. It’s also automatically published to the client for
that particular user.
Basically, it's probably fine to store basic information such as name, address, dob, etc in the profile field, but not a good idea to store anything beyond that as it will, by default, be writeable by the client and vulnerable to malicious users.
I had the same problem and managed to do it only with Accounts.createUser:
Accounts.createUser({
email: email,
password: password,
profile: {
givenName: 'John',
surname: 'Doe',
gender: 'M'
}
}
Thats very simple way and it works. Just add your desired variables in the profile section and it should be ready. Hope it helps someone.
I ended up using https://atmospherejs.com/joshowens/accounts-entry which offers an extraSignUpFields config option.
From the documentation (https://github.com/ianmartorell/meteor-accounts-ui-bootstrap-3/blob/master/README.md):
Custom signup options
You can define additional input fields to appear in the signup form, and you can decide wether to save these values to the profile object of the user document or not. Specify an array of fields using Accounts.ui.config like so:
Accounts.ui.config({
requestPermissions: {},
extraSignupFields: [{
fieldName: 'first-name',
fieldLabel: 'First name',
inputType: 'text',
visible: true,
validate: function(value, errorFunction) {
if (!value) {
errorFunction("Please write your first name");
return false;
} else {
return true;
}
}
}, {
fieldName: 'last-name',
fieldLabel: 'Last name',
inputType: 'text',
visible: true,
}, {
fieldName: 'gender',
showFieldLabel: false, // If true, fieldLabel will be shown before radio group
fieldLabel: 'Gender',
inputType: 'radio',
radioLayout: 'vertical', // It can be 'inline' or 'vertical'
data: [{ // Array of radio options, all properties are required
id: 1, // id suffix of the radio element
label: 'Male', // label for the radio element
value: 'm' // value of the radio element, this will be saved.
}, {
id: 2,
label: 'Female',
value: 'f',
checked: 'checked'
}],
visible: true
}, {
fieldName: 'country',
fieldLabel: 'Country',
inputType: 'select',
showFieldLabel: true,
empty: 'Please select your country of residence',
data: [{
id: 1,
label: 'United States',
value: 'us'
}, {
id: 2,
label: 'Spain',
value: 'es',
}],
visible: true
}, {
fieldName: 'terms',
fieldLabel: 'I accept the terms and conditions',
inputType: 'checkbox',
visible: true,
saveToProfile: false,
validate: function(value, errorFunction) {
if (value) {
return true;
} else {
errorFunction('You must accept the terms and conditions.');
return false;
}
}
}]
});
The official Meteor Guide provides a comprehensive answer with an example code:
The best way to store your custom data onto the Meteor.users collection is to add a new uniquely-named top-level field on the user document.
https://guide.meteor.com/accounts.html#custom-user-data

Resources