Cloud Firestore Database is not displaying users after authentication? - flutter

I am trying to do authentication using createUserWithEmailAndPassword .The user iis getting created since I can signin using the email and password which created using createUserWithEmailAndPassword .But my firestore database is not showing the document which I have created using createUserWithEmailAndPassword().
This is my code:
onPressed: () async {
try {
final newuser = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email ?? 'error',
password: password ?? 'error',
);
if (newuser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => home()),
);
}
} catch (e) {
print(e);
}
I have created 3 users with this method and I'm able to login with these credential but these users are not showing in my Firestore Database.

As #ashish already mentioned, you need to store all your extra parameters in the firestore as documents. A better way to implement this is to use different function to register user and create a user document related to that registered user.
Below is an example I created to help out!
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
void main() {
String email = "test#test.com";
String password = "123456";
String firstName = "test";
String lastName = "test";
String phoneNumber = "09876543456";
/// This is the function to create new user
Future<void> createUser(
email,
password,
firstName,
lastName,
phoneNumber,
/*... and any other params you wish to collect */
) async {
// firebase auth
final FirebaseAuth auth = FirebaseAuth.instance;
// firestore db
FirebaseFirestore db = FirebaseFirestore.instance;
// try-catch creation process to accurate exception
try {
final credential = await auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// get user id
String userID = credential.user!.uid;
// creating user profile on db
await db.collection("users").doc(userID).set({
"id": userID,
"firstName": firstName,
"lastName": lastName,
"phoneNumber": phoneNumber,
// ... other params
});
print("Signed up successfully!");
} on FirebaseAuthException catch (error) {
print("Something is wrong: $error");
}
}
/// this is the create button
TextButton(
onPressed: () async {
await createUser(
email,
password,
firstName,
lastName,
phoneNumber,
/*... and any other params you wish to collect */
);
},
child: const Text("Create test user"),
);
}
Let me know if you need anything else :). BYE!!!

To store the data in the database you need to use a Firestore instance to store data in firebase Firestore.
onPressed: () async {
try {
final newuser = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email ?? 'error',
password: password ?? 'error',
);
await FirebaseFirestore.instance.collection('Users').doc(newuser!.uid).set({
email: newuser.email
});
if (newuser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => home()),
);
}
} catch (e) {
print(e);
}
}
You need to put the data which you want to store in firestore in set() function.

Firebase Authentication data are show into the login into firebase then on tap of Authentication options menu -> user section , you can view store 3 users data in this section

Related

Can we set user displayName in firebase using password authentication through flutter? [duplicate]

I can save the email and the password with Firebase Authentication. I also save this information with Cloud Firestore. But how can I add and save the displayName after registering?
my code:
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData('User', user.email, 'test.de/test.png', user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
the register form button:
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.registerWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
error = 'Valid email, please';
loading = false;
});
}
}
}
You can use updateProfile method given in the FirebaseUser class to update the name and photo url.
updateProfile({String displayName, String photoURL}).
For email you can use the different method
updateEmail(String newEmail) which is a async method.
Or to save the username directly into the firestore, after successful login you can use 'set' method of the FirebaseFirestore to save email, password and the username.
Here's the code if you want to save the Username together with the email and password
final FirebaseAuth _auth = FirebaseAuth.instance;
//register with email & password & save username instantly
Future registerWithEmailAndPassword(String name, String password, String email) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
user.updateProfile(displayName: name); //added this line
return _user(user);
} catch(e) {
print(e.toString());
return null;
}
}
late User userFirebase;
Future<UserCredential> userCredential =await //Your code signin or signup
await userCredential.then((UserCredential value) {
userFirebase = value.user!;
});
await userFirebase.updateDisplayName(event.name);
You can use updateDisplayName() and updatePhotoURL() methods on a User object to add the displayName/profile image to Firebase user.
final userCredential = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
//After creating a user in Firebase, we then are able to change name/pictue
await userCredential.user?.updateDisplayName(name);
await userCredential.user?.updatePhotoURL(imageUrl);
As of october 2021, updateProfile() is deprecated, and you should use updateDisplayName() and updatePhotoURL() instead.

Flutter, How to use multiple shared preferences

My goal was to avoid users getting logged out once they close and reopened the app. So, I used shared_preferences to store the user's email and password locally so, that whenever the user reopens the app I could use firebase's signInWithEmailAndPassword and provide locally stored email and password to it. I used setString() to store email password but I was able to store only email and not the password, I get the error "Password is null" How do I solve this. Did I do the code right?
Storing email and password when user registers in app
onPressed: () async {
try {
final user =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (user != null) {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString(
'email',
email,
);
sharedPreferences.setString('password', password);
Get.to(() => const BorrowerList());
}
} catch (e) {
Get.snackbar('Error', e.toString(),
backgroundColor: (Colors.red));
}
},
fetching email password and login after reopening.
#override
void initState() {
super.initState();
validateUserAuth();
}
final _firestore = FirebaseFirestore.instance;
void validateUserAuth() async {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
var obtainedEmail = sharedPreferences.getString('email');
var obtainedPassword = sharedPreferences.getString('password');
if (obtainedEmail != null || obtainedPassword != null) {
setState(() {
loggedinUserEmail = obtainedEmail!;
loggedinUserPassword = obtainedPassword!;
});
if (loggedinUserEmail != null || loggedinUserPassword != null) {
final loggedinuser = await auth.signInWithEmailAndPassword(
email: loggedinUserEmail, password: obtainedPassword!);
if (loggedinuser != null) {
Get.to(() => const BorrowerList());
}
}
} else {
Get.to(() => AuthScreen());
}
}
The error is apparent.
You can't save a null value in shared_preferences.
Your code is not complete. somehow your password variable is null.
You can paste complete code so we can help you better
Can you provide more information about the project? So far, it's obvious that you're trying to store a null value in shared_preferences. You can't do that. I'm pretty sure the problem is that when the user enters a password, it's not stored in the password variable here:
try {
final user =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (user != null) {
final SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
sharedPreferences.setString(
'email',
email,
);
// NULLABLE VARIABLE!
sharedPreferences.setString('password', password);
Get.to(() => const BorrowerList());
}
} catch (e) {
Get.snackbar('Error', e.toString(),
backgroundColor: (Colors.red));
}
},
Additionally, it is not recommended to use shared_preferences for storing sensitive data. Flutter Secure Storage is much better suited for this.

onPressed takes 2 clicks to complete nested functions

When a user enters their information in an overlay, presses submit, 4 things should happen.
User's account is registered in firestore
User has a document created with their info
the overlay is closed
nav() page is called
On the first click, [1] happens and then stops at the collection reference.
On the second click, [1] fails, but [2-4] successfully go through. I think it has to do with when the user info not coming back from the registry fast enough but the prints are coming back correctly so I'm not sure.
onPressed function in overlay
onPressed: () async{
await register(_email, _password);
await signUp(_email, firstName, lastName, userName);
hideNewUserOverlay();
var navTab = 2;
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => const Nav(),
settings: RouteSettings(arguments: navTab)
));
}
Register and Sign Up
Future<void> register(String email, String password) async {
try {
// ignore: unused_local_variable
await auth.createUserWithEmailAndPassword(
email: email,
password: password); // <-- user account is created on first press
} catch (e) {
debugPrint('>> register: create new user error');
}
user = auth.currentUser!;
debugPrint(' register: current user got');
String userID = user.uid;
debugPrint(' register: user.id = $userID');
}
Future<void> signUp(
String email, String firstName, String lastName, String userName) async {
user = auth.currentUser!;
debugPrint('>> signUp: current user got');
String userID = user.uid;
debugPrint(' signUp: user.id = $userID'); // all debugs print out correctly
try {
debugPrint(' signUp: document creation code Start');
await collectionReference.doc(userID).set({ // first click stops here, takes 2 clicks to finish
'profileImageUrl': 'https://firebasestorage.googleapis.com/v0/b/commentaries-d82cd.appspot.com/o/defaultProfileImage.png?alt=media&token=07e4d649-3da7-4f9f-8cf9-062ac9cc9507',
'userID': userID,
'accountCreated': DateTime.now(),
'email': email,
'userName': userName,
'firstName': firstName,
'lastName': lastName,
});
debugPrint(' signUp: User Document Created');
} catch (e) {
debugPrint(' signUp: create new user error');
}
}
I think it doesn't work all at once because you are making asynchronous calls but your onPressed function is not async
Try this:
onPressed: () async{
await register(_email, _password);
await signUp(_email, firstName, lastName, userName);
hideNewUserOverlay();
var navTab = 2;
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => const Nav(),
settings: RouteSettings(arguments: navTab)
));
}
You can add callback to your functions, so you know they are done.
See:
Future<void> register(String email, String password, VoidCallback callback) async {
try {
// ignore: unused_local_variable
await auth.createUserWithEmailAndPassword(
email: email,
password: password); // <-- user account is created on first press
} catch (e) {
debugPrint('>> register: create new user error');
}
user = auth.currentUser!;
debugPrint(' register: current user got');
String userID = user.uid;
debugPrint('register: user.id = $userID');
callback(); //here you will send the flag informing the job is done.
}
Now let´s do the same with the other function.
Future<void> signUp(
String email, String firstName, String lastName, String userName, VoidCallback callback) async {
user = auth.currentUser!;
debugPrint('>> signUp: current user got');
String userID = user.uid;
debugPrint(' signUp: user.id = $userID'); // all debugs print out correctly
try {
debugPrint(' signUp: document creation code Start');
await collectionReference.doc(userID).set({ // first click stops here, takes 2 clicks to finish
'profileImageUrl': 'https://firebasestorage.googleapis.com/v0/b/commentaries-d82cd.appspot.com/o/defaultProfileImage.png?alt=media&token=07e4d649-3da7-4f9f-8cf9-062ac9cc9507',
'userID': userID,
'accountCreated': DateTime.now(),
'email': email,
'userName': userName,
'firstName': firstName,
'lastName': lastName,
});
debugPrint(' signUp: User Document Created');
callback();
} catch (e) {
debugPrint(' signUp: create new user error');
}
}
now you can make this with steps:
onPressed: () async{
await register(_email, _password, (){
await signUp(_email, firstName, lastName, userName, (){
hideNewUserOverlay();
var navTab = 2;
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => const Nav(),
settings: RouteSettings(arguments: navTab)
));
});
});
}
Explaination: What I did was to place the next step inside the callback. So, you know everything will continue only when you really want it to.
next things to do to make your code better:
Named paramters to help code reading.
Create functions to callbacks, making the code more readable too and maintenable.
remove the awaits no more needed.
Create a Loading while the process go, as this can take long.
Create a block to not allow multiples clicks in this button.
Create callbacks to handle failures.

How to get the current UserId from Firestore?

I have a collection users where every user has his own document. Now I want to create a subcollection to store more data related to a specific user.
This is the code so far:
class DatabaseService {
Future isUserRegistered(String uid) async{
return await FirebaseFirestore.instance.collection('users')
.where('uid', isEqualTo: uid)
.get();
}
Future registerNewUser(email, password, uid) async{
return await FirebaseFirestore.instance.collection('users')
.doc(uid).set(
{
"email": email,
"password": password,
"uid": uid,
"token": -1,
"userGoal": false,
"userGender": false,
},
);
}
I created a save function but instead of storing data in a subcollection within the document with the current uid, firestore creates a new document named 'uid'. How to fix that?
Future saveInSubcollectionToRemote() async{
Map<String, dynamic> data = UserManager.userWeights;
return await FirebaseFirestore.instance.collection('users')
.doc('uid')
.collection('weights')
.doc(data['userWeight'])
.set(data);
}
class UserManager {
static Map<String, dynamic> userWeights = {'weights': []};
}
EDIT
This is my google authentication, here i get an id but instead of this id i want the uid
///Authentication
void signInGoogle(context) {
DatabaseService handler = new DatabaseService();
_googleSignIn
.signIn()
.then((userdata) => {
print(userdata.toString()),
handler
.isUserRegistered(userdata.id.toString())
.then((value) => {
if (value.docs.length == 0)
{
print("Not registered"),
registerUserToApp(
context, userdata.email.toString(), "password", userdata.id.toString())
}
else
{
print(value.docs[0].data().toString()),
UserManager.userdata = value.docs[0].data(),
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return NavBar();
},
),
(route) => false,
),
}
})
.catchError((e) => {
showAlertDialog(
context, "Error", ""),
})
})
.catchError(
(e) => {showAlertDialog(context, "Error", "")});
}
void registerUserToApp(context, email, password, uid) {
DatabaseService handler = new DatabaseService();
try {
handler.registerNewUser(email, password, uid).then((value) => {
showAlertDialog(context, "Congratulations!",
"You registered to the app"),
});
} catch (error) {
print(error.toString());
showAlertDialog(context, "Error", "");
}
}
}
The uid in your code is typically the unique identified of the user. Firestore itself has no knowledge of such a uid. Instead, the uid comes from the identity provider that you use.
You could use the user ID from Google Sign-in to identify the user in Firestore, but it's more common to sign in with Firebase (too).
Once you've signed in to Google, you can use those credentials to sign in to Firebase Authentication by calling signInWithCredential as shown in the documentation on social authentication.
Once you're signed in to Firebase Authentication you'll get a UID from Firebase Authentication, which you can then use to identify the user's documents in Firestore (and later also secure access to those documents).
Once you've done that, you can get the current user (and from there their UID) through FirebaseAuth.instance.currentUser (once) or FirebaseAuth.instance.currentUser() (continuous) and then again use that in your Firestore calls.
Using doc('uid') is setting your document id as 'uid'. This is whats causing your issue.
Try this:
Future saveInSubcollectionToRemote(String uid) async{
Map<String, dynamic> data = UserManager.userWeights;
return await FirebaseFirestore.instance.collection('users')
.doc(uid)
.collection('weights')
.doc(data['userWeight'])
.set(data);
}
pass in uid like you did in registerNewUser()

Flutter, firebase. I want to show my registration form data other than the email and password and connect to a unique uid

Register Screen On Pressed method given, I believe there is a problem with calling Firebase user = result.user
onPressed: () async {
if(_formKey.currentState.validate()){
setState(() => loading = true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password);
FirebaseUser user = result.user;
await DatabaseService(uid: user.uid).newUserInfo(
_nameC.text,
_cityC.text,
_contactnoC.toString()
);
if(result == null) {
setState(() {
error = 'Please supply a valid email';
loading = false;
});
}}},
// Database backend
class DatabaseService {
final String uid;
DatabaseService ({this.uid});
final CollectionReference userdata2 = Firestore.instance.collection('UserData');
Future newUserInfo(String name, String city, String contactno) async {
return await userdata2.document(uid).setData({
'name' : name,
'city' : city,
'contactno' : contactno
});
}}
// authentication backend
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
DatabaseService(uid: user.uid);
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
} }
// user.dart
class User {
final String uid;
User({this.uid});
}