Reputation: 43
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" />
<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