FS Document is not getting created after user is registered - flutter

When a user submits their information on the "Signup page", the user should have
an account registered within fire store and
a fire store document created with all of their information inside.
The user account gets registered fine, but the document never gets created. I'm not getting any error messages so I'm trying to use debug prints to find out where things are going wrong.
Debug Prints:
>> login: signUp // this starts the signUp function
>> login: Start hideNewUserOverlay // hide overlay prints before signUp finishes
>> signUp: current user got // the following prints are from signUp
>> signUp: user.id = L8pD6tng5NTAACN7VygK93F6crg1
>> signUp: document creation code Start // then nothing happens after this
Future that is supposed to register the user and create document: // this will eventually pass in first/last names too, that's why I'm using this function
Future<void> signUp(String email, String password) async {
try {
// ignore: unused_local_variable
UserCredential result = await auth.createUserWithEmailAndPassword(email: email, password: password); // <-- user account is created on first press
} catch (e) {
debugPrint('>> Authentication: create new user error');
}
user = auth.currentUser!;
debugPrint('>> signUp: current user got');
String userID = user.uid;
debugPrint('>> signUp: user.id = $userID'); // all debugs print out correctly here, even userID
debugPrint('>> signUp: document creation code Start');
await collectionReference.doc(userID).set({ // code does not run
'userID': userID,
'accountCreated': DateTime.now(),
'email': email,
});
debugPrint('>> Authentication: User Document Created');
}
Signup page:
onPressed: () {
debugPrint('>> login: signUp');
signUp(_email, _password); // this line should finish before the next debug statement is printed but it does not
debugPrint('>> login: Start hideNewUserOverlay'); // prints before signUp() is done
hideNewUserOverlay(); // this will close the Signup page
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => const Nav(),
));
}
At the bottom of the code, the document will get created if I route to a different class. Nav() >> Verify(). The weird part is that Verify does not take in any user information. Verify() has a timer so maybe that has something to do with it? I think it is because the signup() function does not complete before the overlay is hidden. Maybe Nav() needs init state?

Putting await in from of a statement that returns a Future makes that line block the rest of the execution. It does not however make any other call wait.
If you want to wait until signUp is done, use await there too:
await signUp(_email, _password);
That does mean you'll need to mark onPressed as an async method too.
If that is not an option, you can always use then:
onPressed: () {
debugPrint('>> login: signUp');
signUp(_email, _password).then(() {
debugPrint('>> login: Start hideNewUserOverlay'); // prints before signUp() is done
hideNewUserOverlay(); // this will close the Signup page
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => const Nav(),
));
}
}

Related

User info getting saved even after logout. Flutter Firebase

I want to sign a user out and sign a new user in. I am not able to do that. The information of previous user is somehow being saved, I can't deduce how. Any idea what should I do? I followed the answer in this post : How to Signout a user in Flutter with Firebase authentication
added await keyword but its still not quite working
This is the code to it. I am going to Log in page but after login previous users information is being shown to this new user
Future<void> signOut(BuildContext context) async {
try {
await firebaseObject.signOut().then((value) {
Timer(const Duration(seconds: 1), () {
Navigator.pushReplacementNamed(context, RoutesName.login);
});
Utils.flushBarErrorMessage("Logged out successfully", context,
color: Constants.blueColor);
});
} on FirebaseAuthException catch (e) {}
}

How to update phone number in Firebase when sim card is changed? [duplicate]

In my Flutter app I use Firebase's phone number authentication as my main form of authentication. After authenticating, I create a user in my users collection with these details:
{
phoneNumber: FirebaseAuth.instance.currentUser().phoneNumber,
displayName: 'Comes from user textbox',
...
}
But say one day a user want's to change their phone number. How do I do this? Because I cannot simply change the user's phone number in the document, because the phone number needs to be authenticated. And after authentication, the user gets a new authUID. Which should then be a new user?
Could someone explain the logic behind a user that wants to keep their profile details but change their number.
In order to achieve this, you can use User.updatePhoneNumber. This allows you to update the phone number of a user.
You would use it in the same manner that you also authenticated with phone number in the first place (using signInWithCredential), i.e. you retrieve a credential using FirebaseAuth.verifyPhoneNumber and pass the credential that you get from either verificationCompleted or your user when they enter the SMS code they received. I will only sketch out what this would look like as I assume that you know how to perform this task:
FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phoneNumber,
timeout: const Duration(minutes: 2),
verificationCompleted: (credential) async {
await (await FirebaseAuth.instance.currentUser()).updatePhoneNumber(credential);
// either this occurs or the user needs to manually enter the SMS code
},
verificationFailed: null,
codeSent: (verificationId, [forceResendingToken]) async {
String smsCode;
// get the SMS code from the user somehow (probably using a text field)
final AuthCredential credential =
PhoneAuthProvider.getCredential(verificationId: verificationId, smsCode: smsCode);
await (await FirebaseAuth.instance.currentUser()).updatePhoneNumber(credential);
},
codeAutoRetrievalTimeout: null);
When updatePhoneNumber is called, you probably also want to update your database document. Alternatively, you could listen to onAuthStateChanged and update your document this way.
async function save(phone: string, e) {
e.preventDefault();
const { currentUser:fuser } = firebase.auth();
if(fuser && fuser.phoneNumber !== phone) {
try {
const verifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
callback: (response) => console.log('callback', response),
size: 'invisible',
});
const phoneProvider = new firebase.auth.PhoneAuthProvider();
const id = await phoneProvider.verifyPhoneNumber(phone, verifier);
const code = window.prompt('Bitte zugeschickten Code eingeben');
const cred = firebase.auth.PhoneAuthProvider.credential(id, code);
await fuser.updatePhoneNumber(cred);
console.log('phone number changed', id, cred, fuser);
setSuccess(true);
} catch(e) {
console.error(e);
}
}
}

Errors in my firebase delete account code in my flutter app

I have created a delete account page in my Flutter app . And I have written a code for the onPressed function.
My logic: On the delete account page I have added 2 text fields, they are: email and password, when the user enters his email and password and clicks on the Delete Account button, I want firebase to check whether the credentials are correrct. Only if the credentials are correct I want firebase to delete the account.
But I'm getting an error:
The method 'delete' isn't defined for the type 'AuthUser'.
Try correcting the name to the name of an existing method, or defining a method named 'delete'.
onPressed code:
onPressed: () async {
final email = _email.text;
final password = _password.text;
try {
await AuthService.firebase().logIn(
email: email,
password: password,
);
final user = AuthService.firebase().currentUser;
await user?.delete();
} on UserNotFoundAuthException {
await showErrorDialog(
context,
'User not found',
);
} on WrongPasswordAuthException {
await showErrorDialog(
context,
'Wrong credentials',
);
} on GenericAuthException {
await showErrorDialog(
context,
'Authentication error',
);
}

After first login red null error comes just for a second

When i run the app and log-in / or already logged in before closed app => "Null check operator used on a null value" error pops up and it goes away just in a second. I guess user going to page before data came up.
If i sign-out and log in with another acc. Red screen wont came up but the last users data appears just for a second then current users data comes after. Could you please help me about this.
My primitiv Sign-in method
Future signIn() async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: emailController.text.trim(),
password: passwordController.text.trim(),
);
print('Signed In');
} on FirebaseAuthException catch (e) {
print (e);
Utils.showSnackBar(e.message);
}}}
User Provider
class UserProvider with ChangeNotifier {
User? _user;
final AuthMethods _authMethods = AuthMethods();
User get getUser => _user!;
Future<void> refreshUser() async {
User user = await _authMethods.getUserDetails();
_user = user;
notifyListeners();}}
The code i use refresh User welcomepage level
class _welcomePageState extends State<welcomePage> {
void initState() {
super.initState();
addData();
}
addData() async{
UserProvider _userProvider = Provider.of(context,listen: false);
await _userProvider.refreshUser();
}
#override
if that codes not enough to solve i can share all could you please help me to solve this problem.
You are force-unwrapping here :
User get getUser => _user!;
which means when you hot-reload the app it is null and the crash appears until it is null, you should make it optional and provide a default value so it doesn't crash.

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.