B_M
B_M

Reputation: 173

How can I filter this data?

I have a productSlice as follows:

export const productSlice = createSlice({
  name: 'productSlice',
  initialState: {
    products: [
      {
        id: 0,
        name: 'AutoPart 1',
        desc:
          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
        price: 800,
        picture: IMAGES.aTeamPerfomance12CircuitWires,
        currentQuantity: 1,
        category: 'Wiring',
      },
      ...
    ],
    hasAppliedFilter: false,
    filteredList: [],
    searchResult: [],
    selectedCategory: 0,
    categories: [
      'All',
      'Engine & Emissions',
      'Lamps & Lighting',
      'Brakes & Suspension',
      'Tyres & Rims',
      'Wiring',
      'Electrical',
    ],
  },
  reducers: {
    filterList: (state, action) => {
    },
    searchList: (state, action) => {
    },
  },
});

In ProductSection.js, I have categories setup as below:

<ScrollView
          horizontal
          showsHorizontalScrollIndicator={false}
          style={{margin: 10, maxHeight: 40}}>
          {categories.map((item, index) => {
            return (
              <TouchableOpacity
                style={{
                  marginBottom: 5,
                  padding: 2,
                }}
                onPress={() => dispatch(filterList(index))}>
                <Text
                  style={{
                    fontWeight: 'bold',
                    marginRight: 30,
                    opacity: index == selectedCategory ? 1 : 0.2,
                    color: theme.text,
                    ...FONTS.body3,
                  }}>
                  {item}
                </Text>
              </TouchableOpacity>
            );
          })}
        </ScrollView>

What I want to achieve is when a category is pressed, the products will be filtered to show only those that match the category. But when the category value is 'All', all the products will be displayed. The filteredList array is meant for products filtered based on the category selected and searchResult is for products that have been filtered based on input values from the user. hasAppliedFilter is supposed to check if the user is filtering, else, display all the products.

Upvotes: 0

Views: 56

Answers (1)

Chetan Jain
Chetan Jain

Reputation: 241

I assume you want to implement a search input and a category tab like in an ecommerce application.

Step 1:

Your Redux state must look like it as per because final products are computable from them (See Thinking in React Step 3 (https://reactjs.org/docs/thinking-in-react.html)) 
- filteredList: [],
+ selectedCategory:string,
- searchResult: [],
+ searchText:string,

Step 2: In search component extract the state and filter them

import { FC } from 'react'
import { useSelector } from 'react-redux'

export const isEmpty = (param: any) => !param ? true : false
export const isTextContainSearchText = (text: string, searchText: string) => text.indexOf(searchText) > -1

export const isEmptyString = (p: string) => {
    if (isEmpty(p) || p!.trim().length === 0) {
        return true
    } else return false
}


export const filterProducts = (selectedCategory: any, searchText: any, products: any[]) => {
    var r = products;
    if (selectedCategory !== 'All') {
        r = products.filter(({ category }) => category === selectedCategory)
    }

    if (!isEmptyString(searchText)) {
        searchText = searchText.toLowerCase()
        r = r.filter(({ name }) => isTextContainSearchText(name.toLowerCase(), searchText))
    }
    return r
}

const SearchComponent: FC = () => {

    const { selectedCategory, searchText, products } = useSelector(state => state.product)
    const ps = filterProducts(selectedCategory, searchText, products)

    return (
        <div>
            {JSON.stringify(ps)}
        </div>
    )
}

Note: Below are some jest test cases for filterProducts

import { filterProducts } from "."

test('should filterProducts', () => {
    const products = [
        {
            id: 0,
            name: 'AutoPart 1',
            desc:
                'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
            price: 800,
            currentQuantity: 1,
            category: 'Wiring',
        },
    ]
    expect(filterProducts('All', '', products)).toHaveLength(1)
    expect(filterProducts('Wiring', '', products)).toHaveLength(1)
    expect(filterProducts('Electicals', '', products)).toHaveLength(0)
    expect(filterProducts('All', 'ram', products)).toHaveLength(0)
})

enter image description here

Upvotes: 1

Related Questions