Linking Firebase Authenticated user with 'users' collection in Flutter - flutter

New to flutter, and first post here!
I am building a mobile app with flutter, using Firebase and Cloud Firestore. Each user, when authenticated (by email and password), is also currently then added to a 'users' collection in Firestore - like this:
sign up method:
Future signUp() async {
if (passwordConfirmed()) {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
// add user details
addUserDetails(
_firstNameController.text.trim(),
_lastNameController.text.trim(),
_emailController.text.trim(),
_baseStationController.text.trim(),
);
}
}
Future addUserDetails(String firstName, String lastName, String email,
String baseStation) async {
await FirebaseFirestore.instance.collection('users').add({
'first name': firstName,
'last name': lastName,
'email': email,
'base station': baseStation,
});
}
The signup() method is called when they input their information into text fields within a form, and click a button. This works successfully, and my user collection receives the data, and sign in/out works as it should.
Those users have a 'base station' (which is stored as a field within that users document in Firestore) which is their place of work. I want to show a welcome screen when they log in, so that the current users 'base station' is displayed.
I can access their email address using:
final thisUser = FirebaseAuth.instance.currentUser!;
and then for example to show this when they log in:
Text('Hello, ${thisUser.email!}')
this works no problem, however...
I can't work out how their authentication then links to the collection, so I want to show the 'base station' for the 'currentUser' for example when they log in (I don't want them to have to select their base station every time from a picker when they've already provided the information on sign up.
As an aside - I can also (separately) successfully read the data from the collection and (for example) create a listView builder with the users collection information, but this is for all users, and not specifically the 'currentUser' that is logged in.
All help gratefully received, apologies if I have missed anything.

update addUserDetails as follows
Future addUserDetails(String firstName, String lastName, String email,
String baseStation) async {
await FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).set({
'first name': firstName,
'last name': lastName,
'email': email,
'base station': baseStation,
});
if you then want to get specific user detail then use the code as follows
final user = await FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).get();

Related

How to store default userName, themeMode and themeColor to Cloud Firestore after creating new user in Flutter?

When a new user is created in Firebase, I want to create a collection of user preferences and save it to Cloud Firestore as well. All defaulted to username String 'John Doe', thememode ThemeMode.light and themecolor FlexScheme.money (using flexcolorscheme package).
I can store Strings and int's (works fine with my code), but not ThemeModes apparently and I don't know how to solve this correctly.
I created a PrefService class:
class PrefService {
//Declare a nullable String to hold user unique ID
final String? uid;
//When we call PrefService, require to insert user unique ID
PrefService({this.uid});
final CollectionReference<Object?> userPreferences =
FirebaseFirestore.instance.collection('userPreferences');
Future<dynamic> updateUserPreferences(
String name,
ThemeMode themeMode,
FlexScheme themeColor,
) async {
//If document doesn't exist yet in Firebase, it will be created under user unique ID
return userPreferences.doc(uid).set(<String, dynamic>{
'name': name,
'themeMode': themeMode,
'themeColor': themeColor,
});
}
}
And an AuthService class:
class AuthService {
//Sign UP user only with email and password
Future<void> signUp({
required String email,
required String password,
required BuildContext context,
}) async {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password,
);
//After creating a user, create a database file under user unique ID as well
//Store default name, themeMode and themeColor, which can be adjusted later by user.
Logger().i('Database record created for user');
await PrefService(uid: FirebaseAuth.instance.currentUser!.uid)
.updateUserPreferences(
'John Doe',
ThemeMode.light,
FlexScheme.money,
);
etc...
When I set all parameters of updateUserPreferences() to type String, everything works and I get a nice collection under a unique user ID. But it does not let me store parameter of type ThemeMode:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument: Instance of 'ThemeMode'
Why can I store a String, but not a ThemeMode? I want users to be able to change these settings in a SettingsScreen(), but how should I store them correctly?
I am aware of the existence of SharedPreferences, but I want to do it this way. If anyone can show me how (and why) I should handle this, it would be greatly appreciated.
Objects cannot be saved in firebase directly. If it is Model you can store it in map format.
In your case shore the them mode as String or int i.e. 0 for light and 1 for dark and convert it when you read the data.

Firebase Auth Reset Password (Flutter) - Get the new password

In my Flutter app, there's an admin who creates employee accounts including their passwords. They can however change their passwords later.
The admin can also remove employees
await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: employee.email,
password: employee.password);
await FirebaseAuth.instance.currentUser!.delete();
I call the signInWithEmailAndPassword with the employee email & password & then delete the user from the admin panel
However, if the employee resets the password, the admin can no longer remove this employee as I lose track of the new password
How can I get the new password when someone calls
await FirebaseAuth.instance
.sendPasswordResetEmail(email: email,)
.then((value) {});
That's pretty odd! Why would an admin need to know the passwords of every employee?
I'd suggest you set up a backend cloud function to do the removal process. On Firebase Admin SDK you can simply call the deleteUser method on the Auth object.
getAuth()
.deleteUser(uid)
.then(() => {
console.log('Successfully deleted user');
})
.catch((error) => {
console.log('Error deleting user:', error);
});
Here's the detailed document: https://firebase.google.com/docs/auth/admin/manage-users#delete_a_user

Add subcollection of comments to desired post

So my comments are getting added to the correct post when the comment is made by the author on their own post, like so
The Firestore code updated test:
Future<String> postComment(String postId, String text, String authorId,
String name, String profilePic) async {
String res = 'Some Error occurred';
try {
if (text.isNotEmpty) {
String commentId = const Uuid().v1();
await FirebaseFirestore.instance
.collection('posts')
.doc(authorId)
.collection('userPosts')
.doc(postId)
.collection('comments')
.doc(commentId)
.set({
'profilePic': profilePic,
'name': name,
'uid': authorId,
'text': text,
'commentId': commentId,
'datePublished': DateTime.now()
});
res = 'success';
}
} catch (e) {
res = e.toString();
}
return res;
}
The desired structure of how the comments should get added: posts>UID(of poster)> userPosts(List of their posts)>postID>append comment to this postId as a subcollection.
Now, when I try to create a comment on a post made by another user, a new collection gets started with the ID of the post as its collection name. The postId it gets is the CORRECT id, however, the actual comment itself doesn't get added to the collection of THAT post. As you can see from the circle in the second image, the IDs match, however, the comment made doesn't go where it's intended, as it does in the first image. Does anyone know how I can fix this?
Image with new code test, new collection gets made with the UID of the person who's post I am commenting on, doesn't get added to the subcollection of the actual postId
When you're using the following reference:
await FirebaseFirestore.instance
.collection('posts')
.doc(uid)
.collection('userPosts')
.doc(postId)
.collection('comments')
.doc(commentId)
You're always trying to add data inside a document that corresponds to the currently authenticated user. That's the reason why when you are using the above code with another user, it writes the data to another location. Which location, the one that corresponds to that user.
If you want to write the data under a particular location, you have to create a reference that points to that particular location. For instance, if you want a user to write some data, in a document that corresponds to another user, you have to create a reference that contains that UID. That can be simply done, by adding the ID of the user who creates the post inside the document. In that way, doesn't matter which user reads the post, when you want to write the data, you can use the ID of the user who created the post, to construct the correct path.

How to add new data to firebase

How to add new data to firebase, in the picture on the second column there are users, and on the last one there is my note. This note whas created when user created account, and it whas updated when user logged in, before whas "bad location" etc. My problem is to add new note like this, not update it, kepp it, and at the same time, in the same column have some kind of "new collection" with the same 3 strings, but with different data.
class DataService {
final String uid;
DataService({required this.uid});
final CollectionReference notesCollection =
FirebaseFirestore.instance.collection('Notes');
Future createUserData(String notes, String localisation, String title) async {
return await notesCollection.doc(uid).set({
'notes': notes,
'title': title,
'localisation': localisation,
});
}
Future addData(String notes, String localisation, String title) async {
return await notesCollection.doc(uid).set({
'notes': notes,
'title': title,
'localisation': localisation,
});
}
}
This class shows my createUserData, when my user creates account or loggs in, but how to change "addData" in order to have logic as I described above?
if I understand correctly you want to create a new collection for each documents as history. try this:
notesCollection.doc(uid).collection("historic").add({
'notes': notes,
'title': title,
'localisation': localisation,});

How can i add DocumentID in CollectionReference of cloud firestore? Using flutter

I want to store documentID in my cloud_firestore_database using flutter. I have made a authentication for every User ,so that the data of every User can store individually.Data storing in database in the following way(Student entry => auth(UserId) => vault =>documentID(xj23yvbfvbnbjgkb) => User details)
// collection reference
CollectionReference vaultCollection = Firestore.instance.collection('student entry').document(uid).collection('vault');
vaultCollection.document().setData({
"Entry-time": date,
'image': url,
'fname': name,
'year': year,
'purpose': visiting,
'vehicleno': vehicleno,
'contact': contact,
'Exit-time': "unknown",
'docId'://How can i add documentID ?
});
Use the DocumentReference returned from document(). It contains the randomly generated id before the document is actually added.
DocumentReference doc = vaultCollection.document();
doc.setData({
...
'docId': doc.documentID
});