I am working on a shopping app with firestore as a backend, where users add products to the cart.(Shop -> Product Category -> Product -> Add to cart). There is some weird behavior when the user clicks on the add to cart button. For the first time when the user clicks on Add to cart, the view automatically pops back to the Product category screen. Then if I click on any product category it goes to the product screen and pops back automatically. I am stuck with this issue for a couple of days, Please shed some light on what I am doing wrong. Thanks a ton.
Product
struct Product : Identifiable, Codable {
@DocumentID var id : String?
var name : String?
var price : String?
var available : Bool = false
var quantity : Int = 1
var category : String?
enum CodingKeys: String, CodingKey {
case id, name, price, category, available
}
}
ProductViewModel
public class ProductViewModel: ObservableObject {
@Published var productArray : [Product] = []
@Published var selectedProducts : [Product] = []
@Published var productTotal = ProductTotal(totalAmt: 0)
@Published var productImgDict : [String : String] = [:]
@Published var selectedProduct = Product()
var products : [Product] = []
var dummyProductLst : [Product] = []
var dummyCartItems : [Product] = []
var firestore = Firestore.firestore()
var storageRef = Storage.storage()
init(){
}
func ClickedProduct(product : Product) {
// Single product selection
selectedProduct = product
}
func getClickedProduct() -> Product{
return selectedProduct
}
func setSelectedProduct(product : Product) {
selectedProducts.append(product)
self.dummyCartItems.append(product)
self.setDefaultProductQty(product: product)
}
func setDefaultProductQty(product : Product) {
for index in self.selectedProducts.indices {
if product.id == self.selectedProducts[index].id {
//By default setting the quantity to 1 when adding a product
self.selectedProducts[index].quantity = +1
}else{
print("not matched")
}
}
}
func getSelectedProduct() -> [Product] {
return self.selectedProducts
}
func deleteProduct(index : IndexSet) {
self.selectedProducts.remove(atOffsets: index)
self.dummyCartItems.remove(atOffsets: index)
}
func getTotalAmount() -> ProductTotal {
var totalAmt = 0;
for item in self.selectedProducts {
totalAmt = totalAmt + Int(item.price?.floatValue ?? 0)
}
return ProductTotal( totalAmt: totalAmt)
}
func setQuantity(index : Int, qty : Int = 1) {
self.selectedProducts[index].quantity = qty
}
func setgetUpdatedPrice(index : Int, qty : Int, itemID : String = "") -> String {
var calculatedAmt = 0
if let data = self.dummyCartItems.first(where: {$0.id == itemID}) {
calculatedAmt = Int(data.price?.floatValue ?? 0) * qty
self.selectedProducts[index].price = String(calculatedAmt)
} else {
// item could not be found
}
_ = getTotalAmount()
print(calculatedAmt)
return String(calculatedAmt)
}
}
ProductsView
struct ProductsView : View {
@EnvironmentObject var prodViewModel : ProductViewModel
var columns = Array(repeating:GridItem(.flexible()) , count: 2)
@AppStorage("user_id") var userId = ""
@Binding var catID : String
@State var store : Store
@State private var showToast = false
@State var showCartView : Bool = false
// @State var selectedProds : Product
@State var showDetailView: Bool = false
var body: some View{
ScrollView{
LazyVGrid(columns: columns, spacing:30){
let withIndex = prodViewModel.productArray.enumerated().map({ $0 })
ForEach(withIndex, id: \.element.id){ index, product in
ProductGridView(prodViewModel: _prodViewModel, showToast: $showToast, product: product,store: store)
.onTapGesture {
showDetailView.toggle()
prodViewModel.ClickedProduct(product: product)
}.sheet(isPresented: $showDetailView) {
ProductDetailsView(store: store, showDetailView: $showDetailView)
}
}
}
.padding(.leading, 15)
.padding(.trailing, 15)
.navigationBarItems(trailing:
Button(action: {
self.showCartView.toggle()
}) {
Image(systemName: "cart.fill").imageScale(.large).font(.title3)
}
.overlay(Badge(count: prodViewModel.getSelectedProduct().count))
)
}
.toast(isShowing: $showToast, msg: "Added to cart", img: "cart")
.background(
NavigationLink(
destination: CartView(prodViewModel: _prodViewModel, store: store, selectedCatID: catID),
isActive: $showCartView,
label: {
}
)
)
.onAppear{
prodViewModel.FetchProductByCategory(storeID: store.id ?? "", catID: catID)
}
}
}
ProductGridView
struct ProductGridView: View {
@EnvironmentObject var prodViewModel : ProductViewModel
@EnvironmentObject var partialSheetManager : PartialSheetManager
@Binding var showToast : Bool
var product : Product
var store : Store
var body: some View {
ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)){
VStack(alignment: .center, spacing: 10){
let imgURL = prodViewModel.productImgDict[product.id ?? ""]
AnimatedImage(url: URL(string: imgURL ?? "")).resizable().frame(width: 110, height: 110).padding()
HStack{
Text("₹\(product.price ?? "")")
.foregroundColor(Color.theme.appColor)
.font(.title2).bold()
Spacer(minLength: 20)
if product.available {
Button(action: {
if self.prodViewModel.getSelectedProduct().contains(where: { $0.id == product .id}){
//item found
}else{
// not found in cart - add product to array
if store.id == AppSettings.shared.getStoreID(){
prodViewModel.setSelectedProduct(product: product)
showToast = true
}else{
print("shop is different, you cannot add it")
self.partialSheetManager.showPartialSheet {
ChangeShopView(store: store, product: product)
}
}
}
}, label: {
Image.init(systemName: "cart.badge.plus")
.renderingMode(Image.TemplateRenderingMode?.init(Image.TemplateRenderingMode.original))
.resizable()
.frame(width: 32, height: 30)
}
)
}else{
}
}
HStack{
Text(product.name ?? "")
.font(.title3)
.multilineTextAlignment(.leading)
.foregroundColor(Color.theme.textColor)
Spacer()
}
} .overlay(
Text( product.available ? "" : "NOT AVAILABLE")
.foregroundColor(.white)
.background(Color.red)
.font(.caption)
.clipShape(RoundedRectangle(cornerRadius: 4))
.padding(.horizontal)
,alignment: .center)
.padding(.horizontal, 8)
.frame(width : UIScreen.main.bounds.size.width/2.4)
.background(Color.theme.cardColor)
.cornerRadius( 6)
.shadow(color: Color.black.opacity(0.2), radius:5, x:-5, y:5)
}
}
}
On clicking Add to cart button I am calling the setSelectedProduct method from ProductViewModel. ProductViewModel is an environmentObject. In the console, am getting - Unable to present. Please file a bug.