So right now I'm building a shopping cart using GetX and firebase. I'm trying to write the data to firebase if the user taps add to cart but not allow duplicate entries just increase the quantity #. Right now I'm getting duplicate entries.
class CartController extends GetxController {
static CartController instance = Get.find();
//cart controller for the shopping cart
Rx<double> totalCartPrice = 0.0.obs;
RxList<CartItemModel> products = RxList<CartItemModel>([]);
@override
void onReady() {
super.onReady();
ever(logController.userModel, editTotalPrice);
}
void addToCart(ProductModel product) {
try {
if (_isItemAlreadyAdded(product)) {
Get.snackbar("Check your cart", "${product.name} is already added");
} else {
String itemID = Uuid().v1();
logController.updateUserData({
"cart": FieldValue.arrayUnion([
{
"id": itemID,
"productId": product.id,
// "name": product.name,
"quantity": 1,
"price": product.price,
"image": product.image,
"cost": product.price,
}
])
});
Get.snackbar("Item added", "${product.name} was added to your cart");
}
} catch (e) {
Get.snackbar("Whoops...Cannot add this right now!",
"There was an error adding to cart",
duration: Duration(seconds: 3), backgroundColor: Colors.pinkAccent);
debugPrint(e.toString());
}
}
void deductCartItem(CartItemModel cartItem) {
try {
logController.updateUserData({
"cart": FieldValue.arrayRemove([cartItem.toJson()])
});
} catch (e) {
Get.snackbar("Error", "Cannot remove this item");
debugPrint(e.toString());
}
}
editTotalPrice(LoginUserModel usrModel) {
if (usrModel.cart!.isEmpty) {
print("Cart empty!");
} else if (usrModel.cart!.isNotEmpty) {
totalCartPrice.value = 50;
print("hi");
usrModel.cart!.forEach((cartItem) {
totalCartPrice.value += cartItem.cost!;
});
}
}
bool _isItemAlreadyAdded(ProductModel product) =>
logController.userModel.value.cart!
.where((item) => item.name == product.name)
.isNotEmpty;
void decreaseQuantity(CartItemModel item) {
if (item.quantity == 1) {
deductCartItem(item);
} else {
deductCartItem(item);
item.quantity! - 1;
logController.updateUserData({
"cart": FieldValue.arrayUnion([item.toJson()])
});
}
}
void increaseQuantity(CartItemModel item) {
deductCartItem(item);
item.quantity! + 1;
logger.i({"quantity": item.quantity});
logController.updateUserData({
"cart": FieldValue.arrayUnion([item.toJson()])
});
}
}
and here is my class:
class CartItemModel {
CartItemModel(
{this.productId,
this.id,
this.image,
this.name,
this.quantity,
required this.price,
this.cost});
CartItemModel.fromMap(Map<String, dynamic> data) {
id = data[ID];
image = data[IMAGE];
name = data[NAME];
quantity = data[QUANTITY];
cost = data[COST].toDouble();
productId = data[PRODUCT_ID];
price = data[PRICE];
}
static const COST = "cost";
static const ID = "id";
static const IMAGE = "image";
static const NAME = "name";
static const PRICE = "price";
static const PRODUCT_ID = "productId";
static const QUANTITY = "quantity";
double? cost;
String? id;
String? image;
String? name;
double? price;
String? productId;
int? quantity;
Map toJson() => {
ID: id,
PRODUCT_ID: productId,
IMAGE: image,
NAME: name,
QUANTITY: quantity,
COST: price! * quantity!,
PRICE: price
};
}
and because this is tied into the login session here is my login class:
class LoginUserModel {
String? displayName;
String? email;
String? photoUrl;
String? uid;
List<CartItemModel>? cart;
LoginUserModel(
{this.displayName, this.email, this.photoUrl, this.uid, this.cart});
LoginUserModel.fromSnapshot(DocumentSnapshot<Map<String, dynamic>> snapshot) {
displayName = snapshot.data()!["DISPLAYNAME"];
photoUrl = snapshot.data()!["PHOTOURL"];
email = snapshot.data()!["EMAIL"];
uid = snapshot.data()!["UID"];
cart = _convertCartItems(snapshot.data()!["CART"] ?? []);
}
List<CartItemModel> _convertCartItems(List cartFomDb) {
List<CartItemModel> _result = [];
if (cartFomDb.length > 0) {
cartFomDb.forEach((element) {
_result.add(CartItemModel.fromMap(element));
});
}
return _result;
}
List cartItemsToJson() => cart!.map((item) => item.toJson()).toList();
}
And my login controller:
class LoginController extends GetxController {
static LoginController instance = Get.find();
Rxn<User> fbUser = Rxn<User>();
final googleSignIn = GoogleSignIn();
RxBool isLoggedIn = false.obs;
Rx<LoginUserModel> userModel = LoginUserModel().obs;
String usersCollection = "users";
// Rx<UserModel> usrModel = UserModel().obs;
GoogleSignInAccount? _googleAcc;
LoginUserModel? _userModel;
@override
void onReady() {
super.onReady();
fbUser = Rxn<User>(auth.currentUser);
fbUser.bindStream(auth.userChanges());
ever(fbUser, setInitialScreen);
}
LoginUserModel? get loggedInUserModel => _userModel;
setInitialScreen(User? user) {
if (user == null) {
print("going to login page...");
Get.offAll(() => LoginPage());
} else {
print("The user is ${user.displayName}");
userModel.bindStream(listenToUser());
Get.offAll(() => AppSetup());
}
}
void googleLogin() async {
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_googleAcc = googleUser;
final googleAuth = await googleUser.authentication;
final cred = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
await auth.signInWithCredential(cred).then((res) async {
print('Signed in successfully as ' + res.user!.displayName.toString());
print('email: ' + res.user!.email.toString());
LoginUserModel _newUser = LoginUserModel(
uid: res.user!.uid,
email: res.user!.email!,
displayName: res.user!.displayName,
photoUrl: res.user!.photoURL,
cart: [],
);
_addUserToFB(_newUser, res.user!);
});
} catch (e) {
debugPrint(e.toString());
Get.snackbar("Sign In Failed", "Try again");
}
}
// void signUp() async {
// try {
// await auth
// .createUserWithEmailAndPassword(
// email: email.text.trim(), password: password.text.trim())
// .then((result) {
// String _userId = result.user.uid;
// _addUserToFirestore(_userId);
// _clearControllers();
// });
// } catch (e) {
// debugPrint(e.toString());
// Get.snackbar("Sign In Failed", "Try again");
// }
// }
void signOut() async {
googleSignIn.signOut();
auth.signOut();
}
//maybe add clear controllers method?
updateUserData(Map<String, dynamic> data) {
logger.i("UPDATED");
firebaseFirestore
.collection(usersCollection)
.doc(fbUser.value?.uid)
.update(data);
}
Stream<LoginUserModel> listenToUser() => firebaseFirestore
.collection(usersCollection)
.doc(fbUser.value!.uid)
.snapshots()
.map((snapshot) => LoginUserModel.fromSnapshot(snapshot));
_addUserToFB(LoginUserModel usr, User firebaseUser) {
firebaseFirestore.collection(usersCollection).doc(usr.uid).set({
"displayName": usr.displayName,
"id": usr.uid,
"photoURL": usr.photoUrl,
"email": usr.email,
"cart": usr.cart
});
}
}
My firebase database is pictured below. The cart is in a subcategory (array) as I have it tied to the user who is logged in:
