Cable-Nerd
Cable-Nerd

Reputation: 43

How to correctly set and change filterSlice in viewProducts.jsx file so that it displays filtered products

I am creating an ecommerce website with firebase for login,registration,authentication etc and currently creating an admin route where an admin can add product to it's application(done it), view products, edit products, check how many orders have been placed etc.

so the issue is i'm new to redux tookit so it's a bit confusing for me to implement it in my application, so i'm creating a filterSlice.jsx in redux folder where i am setting the filtering of products by search in admin route, here is the filterSlice.jsx file

// filterSlice.jsx

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  filteredProducts: []
};

const filterSlice = createSlice({
  name: "filter",
  initialState,
  reducers: {
    FILTER_BY_SEARCH(state, action) {
      const { products, search } = action.payload;
      const tempProducts = products.filter(
        (product) =>
          product.name.toLowerCase().includes(search.toLowerCase()) ||
          product.category.toLowerCase().includes(search.toLowerCase())
      );

      state.filteredProducts = tempProducts;
    },
    SORT_PRODUCTS(state, action) {
      const { products, sort } = action.payload;
      let tempProducts = [];
      if (sort === "latest") {
        tempProducts = products;
      }

      if (sort === "lowest-price") {
        tempProducts = products.slice().sort((a, b) => {
          return a.price - b.price;
        });
      }

      if (sort === "highest-price") {
        tempProducts = products.slice().sort((a, b) => {
          return b.price - a.price;
        });
      }

      if (sort === "a-z") {
        tempProducts = products.slice().sort((a, b) => {
          return a.name.localeCompare(b.name);
        });
      }

      if (sort === "z-a") {
        tempProducts = products.slice().sort((a, b) => {
          return b.name.localeCompare(a.name);
        });
      }

      state.filteredProducts = tempProducts;
    },
    FILTER_BY_CATEGORY(state, action) {
      const { products, category } = action.payload;
      let tempProducts = [];
      if (category === "All") {
        tempProducts = products;
      } else {
        tempProducts = products.filter(
          (product) => product.category === category
        );
      }
      state.filteredProducts = tempProducts;
    },

    FILTER_BY_BRAND(state, action) {
      const { products, brand } = action.payload;
      let tempProducts = [];
      if (brand === "All") {
        tempProducts = products;
      } else {
        tempProducts = products.filter((product) => product.brand === brand);
      }
      state.filteredProducts = tempProducts;
    },
    FILTER_BY_PRICE(state, action) {
      const { products, price } = action.payload;
      let tempProducts = [];
      tempProducts = products.filter((product) => product.price <= price);

      state.filteredProducts = tempProducts;
    }
  }
});

export const {
  FILTER_BY_SEARCH,
  SORT_PRODUCTS,
  FILTER_BY_CATEGORY,
  FILTER_BY_BRAND,
  FILTER_BY_PRICE
} = filterSlice.actions;

export const selectFilteredProducts = (state) => state.filter && state.filter.filteredProducts;

export default filterSlice.reducer;

and this is my viewProduct.jsx file where i want to display all products and the user can search products by searching

// ViewProducts.jsx

import React, { useEffect, useState } from "react";
import { deleteDoc, doc } from "firebase/firestore";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";
import { db, storage } from "../../pages/firebase/config";
import Loader from "../loader/Loader";
import { deleteObject, ref } from "firebase/storage";
import { useDispatch, useSelector } from "react-redux";
import { selectProducts, STORE_PRODUCTS } from "../../redux/slice/productSlice";
import {
  FILTER_BY_SEARCH,
  selectFilteredProducts
} from "../../redux/slice/filterSlice";
import "./Admin.css";
import { FaEdit, FaTrashAlt } from "react-icons/fa";

const ViewProducts = () => {
  const [search, setSearch] = useState("")
  const products = useSelector(selectProducts);
  const filteredProducts = useSelector(selectFilteredProducts);
  //pagination states
  const [currentPage, setCurrentPage] = useState(1);
  const [productsPerPage, setProductsPerPage] = useState(10);
  
  // get current products
  const indexOfLastProduct = currentPage * productsPerPage;
  const indexOfFirstProduct = indexOfLastProduct - productsPerPage;
  const currentProducts = filteredProducts.slice(
    indexOfFirstProduct,
    indexOfLastProduct
  );
  const dispatch = useDispatch()
  //pagination states

  return (
    <>
    {isLoading && <Loader />}
      <div>
        <h2>All Products</h2>
        <p>
          <b>{filteredProducts.length}</b> products found
        </p>

        {filteredProducts.length === 0 ? (
          <p>NO Products found</p>
        ) : (
          <div className="table container-fluid ">
            <table className="table ">
              <thead className="product-list justify-content-between align-items-center text-center">
                <tr>
                  <th className=" col">S/N</th>
                  <th className=" col-2">Image</th>
                  <th className=" col-4">Name</th>
                  <th className=" col-2">Category</th>
                  <th className=" col-2">Price</th>
                  <th className=" col-2">Action</th>
                </tr>
              </thead>
              <tbody className="table-body justify-content-between align-items-center text-center">
                {currentProducts.map((products, index) => {
                  const { id, name, price, imageURl, category } = product;
                  return (
                    <tr key={id}>
                      <td>{index + 1}</td>
                      <td>
                        <img
                          src={imageURL}
                          alt={name}
                          style={{ width: "100px" }}
                        />
                      </td>
                      <td>{name}</td>
                      <td>{category}</td>
                      <td>{`$${price}`}</td>
                      <td>
                        <FaEdit size={20} color="green" />
                        &nbsp;
                        <FaTrashAlt size={18} color="red" />
                      </td>
                    </tr>
                  );
                })} 
              </tbody>
            </table>
          </div>
        )}
      </div>
    </>
  );
};

export default ViewProducts;

it is basically giving an error at every filteredProducts logic saying in the console that "caught TypeError: Cannot read properties of undefined (reading 'slice')", currently it is giving an error at

 const currentProducts = filteredProducts.slice(  
    indexOfFirstProduct,
    indexOfLastProduct
  );

when i try to format

const currentProducts = filteredProducts.slice(
    indexOfFirstProduct,
    indexOfLastProduct

it now gives an error at

<b>{filteredProducts.length}</b> products found

saying "caught TypeError: Cannot read properties of undefined (reading 'length')"

so waht i come to know is that it is causing an error at filteredProducts even though i have exported selectFilteredProducts from filter slice as

export const selectFilteredProducts = (state) => state.filter && state.filter.filteredProducts;

and imported it as

import {
  FILTER_BY_SEARCH,
  selectFilteredProducts
} from "../../redux/slice/filterSlice";

assigned it to filteredProducts variable by ising useSelector

const products = useSelector(selectProducts);

maybe iam doing something wrong at filterSlice.jsx maybe it is still a truthy value that is the only reason that comes to my mind

p.s if u want more information just ask maybe ihaven't manage to tell you everything

EDIT: i wasn't configuring the filter reducer in my combineReducers in store.jsx, it was the reason i was getting an error

store.jsx import { configureStore, combineReducers } from "@reduxjs/toolkit" import authReducer from "../redux/slice/authSlice" import productReducer from "../redux/slice/productSlice" import filterReducer from "../redux/slice/filterSlice"

const rootReducer = combineReducers({ auth: authReducer, product: productReducer, filter: filterReducer, // i didn't added this line so was unable to use it

})

const store = configureStore({ reducer: rootReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false, }), });

export default store

Upvotes: 0

Views: 30

Answers (0)

Related Questions