skip to Main Content

I’ll explain in simple language.
I’ve created an eCommerce React App, I made login/signup feature using Firebase, I’m adding Product items to the <Cart /> component (just like every shopping site), everything is working fine BUT NOW I wanna add the product items that user added to his/her cart to the firebase.

This is only for the registered users, which means if the user adds products to the cart it will get stored on firebase and after some time when he/she logs in back, the cart remains the same with the product they added to their cart.

Note: This feature is not for unregistered users as the functionality of adding/removing items is already working fine.

So that’s how I’m getting which user is logged in to the app using firebase, here is the code:-

//App.js    
import Header from "./components/Header/Header";
import Cart from "./pages/Cart";
import Profile from "./pages/Profile";
import { auth} from "./firebase";

function App() {
    const [profileUser, setProfileUser] = useState();
    const [userName, setUserName] = useState(null);
    
    useEffect(() => {
        auth.onAuthStateChanged((user) => {
            if (user) {
                setUserName(user.displayName);              
                setProfileUser(user);
                console.log(user);
            } else {
                setUserName(null);
            }
        });
    }, [userName]);

    return (
        <div>
            <Header loggedUser={userName} />
            <MainWrapper>
                <Routes>
                    <Route path="/cart" element={<Cart />} /> 
                    <Route path="/profile" element={<Profile loggedUser={profileUser}/>} />
                </Routes>
            </MainWrapper>
        </div>
    );
}

2

Answers


  1. For every user, create a sub-collection called "cart".
    And inside "cart", create a document for every items.

    It’ll look something like this (I used orders instead of cart).

    enter image description here

    For the query part,

    const collectionName = `$users/${userId}/cart`
    addDoc(collection(db, collectionName), items)
    
    Login or Signup to reply.
  2. For making a cart which is dependent on user login follow these 3 steps —

    STEP 1. Get userData from a collection of "users" and this collection stores the cart for each user and simply set this cart to our redux cartSlice

    
    // ****** App.js *******
    
    import {onAuthStateChanged} from 'firebase/auth';
    import {auth} from './firebase/firebaseConfig';
    
    import {LOGIN,USER} from './reducers/authSlice';
    
    import { doc, setDoc, getDoc } from "firebase/firestore"; 
    import {database} from './firebase/firebaseConfig';
    import {SET_CART} from './reducers/cartSlice';
    
    
    function App() {
        const isAuthenticate = useSelector(state=>state.authSlice);
        const dispatch = useDispatch();
        const cartItems = useSelector(state=>state.cartSlice);
    
        useEffect(()=>{
            onAuthStateChanged(auth,(user)=>{
                if(user){
                    dispatch(LOGIN());
                    dispatch(USER({email:user.email,id:user.uid}));
                    
                    getDoc(doc(database, "users", user.uid))
                    .then((docSnap)=>{
                        const cartData = docSnap.data().cart;
                        dispatch(SET_CART(cartData));
                    })
                    .catch(err=>console.log(err.message));
    
                }
            })
        },[]);
    
    

    STEP 2. Now make 2 following functions inside cartSlice.js (redux thunk pattern)

    addToCart — add product to cartSlice and firebase at the same time

    removeFromCart — remove product from cartSlice and firebase at the same time

    // ****** cartSlice.js *******
    
    import {createSlice} from '@reduxjs/toolkit';
    import { setDoc } from "firebase/firestore"; 
        
    const cartSlice = createSlice({
        name:"cart",
        initialState:[],
        reducers:{
            SET_CART:{
                reducer(state,action){
                    state = action.payload;
                    return state;
                }
            }
            
        }
    })
    
    export const {SET_CART} = cartSlice.actions;
    export default cartSlice.reducer;
    
    export const addToCart = (cartItems,cartRef,dispatch,product) =>{
    
            
            let updatedCartData = [];
    
            let exist = cartItems.find(item=>item.id === product.id);
            if(!exist){
    
                updatedCartData = [...cartItems,product];
    
            }else{
                updatedCartData = cartItems.map((itemProduct)=>{
    
                    if(itemProduct.id === product.id)
                        return {...itemProduct,quantity:itemProduct.quantity+1,totalPrice:itemProduct.price+itemProduct.totalPrice};
                    
                    return itemProduct;
                })
            }
            
            dispatch(SET_CART(updatedCartData));
            
    
            setDoc(cartRef,{cart:updatedCartData},{ merge: true })
            .then(success=>{})
            .catch(err=>console.log(err.message))
    }
    
    export const removeFromCart = (cartItems,cartRef,dispatch,productId) =>{
    
            let productToRemove = cartItems.find(product=>product.id === productId);
            let updatedCartData = [];
    
            if(productToRemove.quantity > 0){
    
                updatedCartData = cartItems.map((itemProduct)=>{
    
                    if(itemProduct.id === productId)
                        return {...itemProduct,quantity:itemProduct.quantity-1,totalPrice:itemProduct.totalPrice-itemProduct.price};
    
                    return itemProduct;
                })
            }else{
                updatedCartData = cartItems.filter(item=>item.id !== productId);
            }
            
            dispatch(SET_CART(updatedCartData));
    
            setDoc(cartRef,{cart:updatedCartData},{ merge: true })
            .then(success=>{})
            .catch(err=>console.log(err.message))
    }
    

    STEP 3. Now simply use this functions to add and remove cartItems these functions add or remove cartItems from cartSlice and firebase at same time.

    
    //*** cartItem.js ***
    
    import React from "react";
    import { useSelector,useDispatch } from "react-redux";
    import "./Cart.css";
    import { SET_CART, addToCart, removeFromCart } from "../reducers/cartSlice";
    import { doc, setDoc } from "firebase/firestore"; 
    import {database} from '../firebase/firebaseConfig';
    
    
    const CartItem = ({ name, imageURL, quantity, totalPrice, price, id }) => {
      const cartItems = useSelector(state=>state.cartSlice);
      const userData = useSelector(state => state.authSlice );
      const cartRef = doc(database, "users", userData.user.id);
      const dispatch = useDispatch();
    
      const removeHandler = () => {
          let productId = id;
          removeFromCart(cartItems,cartRef,dispatch,productId); 
      };
    
      const addHandler = () => {
          const productToAdd = {id,name,imageURL,price,quantity:1,totalPrice:price};
          addToCart(cartItems,cartRef,dispatch,productToAdd);   
      };
    
      return (
        <div className="cartItem">
          <img src={imageURL} alt="product image"/>
          <h2> {name}</h2>
          <p>${price} /-</p>
          <p>x{quantity}</p>
          <article>Total ${totalPrice}</article>
          <button className="cart-actions" onClick={removeHandler}>
            -
          </button>
          <button className="cart-actions" onClick={addHandler}>
            +
          </button>
        </div>
      );
    };
    
    export default CartItem;
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search