Home > Back-end >  The argument type 'Object?' can't be assigned to the parameter type 'User'
The argument type 'Object?' can't be assigned to the parameter type 'User'

Time:12-30

I'm trying to manage the users roles using firebase auth and firestore but when i try to pass the snapshot.data to the class i create to save the user date in firestore i got this error. i followed a tutorial but my code is different and I'm using a newer version.

class Start extends StatelessWidget {
  const Start({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.hasData && snapshot.data != null) {
          UserHelper.saveUser(snapshot.data!);
          return StreamBuilder<DocumentSnapshot>(
            stream: FirebaseFirestore.instance
                .collection('users')
                .doc(snapshot.data!.uid)
                .snapshots(),
            builder: (BuildContext context,
                AsyncSnapshot<DocumentSnapshot> snapshot) {
              final user = snapshot.data?.data();
              if ((user as Map<String, dynamic>)['role'] == 'admin') {
                return const Home();
              } else {
                return const UserHome();
              }
            },
          );
        } else if (snapshot.hasError) {
          return const Center(child: Text('Algo ha salido mal!'));
        } else {
          return const LoginScreen();
        }
      },
    );
  }
}

CodePudding user response:

You get a stream of nullable User type Stream<User?> authStateChanges()

You should cast away nullability with ! operator: UserHelper.saveUser(snapshot.data!), this is safe to do since you have snapshot.data!=null check in the if clause

As a side note, you might want to reconsider your business logic. authStateChanges() will not be fired on user profile (name, email) changes, but you do update those in the downstream call. userChanges() will be fired on those changes, but if you subscribe to that stream then you dont need to always update last_login. see https://firebase.flutter.dev/docs/auth/start/#userchanges

CodePudding user response:

Your method:

static saveUser(User user) async {
    Map<String, dynamic> userData = {
      "name": user.displayName,
      "email": user.email,
      "last_login": user.metadata.lastSignInTime,
      "created_at": user.metadata.creationTime,
      "role": "user",
    };

accepts a User, but you're passing to it the snapshot.data:

UserHelper.saveUser(snapshot.data);

Which definitely isn't a User.

You probably want a fromJson method on your User class that will convert the JSON to a User. It can look like this, for example:

class User {
  String id;
  String name;
  User({required this.id, required this.name});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
    );
  }
}

And then you would call it:

UserHelper.saveUser(User.fromJson(snapshot.data()!));
  • Related