npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

custom-filter-react

v1.6.4

Published

A library for filtering data

Downloads

24

Readme

Props to pass in

1. filterConfigurations

  • Required to pass in
  • Format: Array of objects
  • Used for displaying desired filters
  • E.g:
   const filterConfigurations = [
   {
     type: "Dropdown",
     placeholder: "Select Category",
     multiSelect: true,
     field: "Country",
     dropdownStyles: { border: "1px solid #ccc" },
     className: "custom-dropdown",
     style: { width: "200px" },
   },
   {
     type: "NumberInput",
     range: true,
     field: "Number",
     placeholder: "Number",
   },
   {
     type: "DateInput",
     range: true,
     field: "Dateline",
     formatStyle: "large",
     firstPlaceHolder: "Start Date",
     secondPlaceHolder: "End Date",
     firstLabel: "Select Date Range",
     button: true,
   },
   {
     type: "CheckboxInput",
     field: "Optional",
     label: "Optional",
     color: "success",
   },
   {
     type: "TextField",
     field: "Name",
     placeholder: "Name",
     width: "30",
   },
 ];

2. url

  • Required to pass in
  • Format: String
  • Used to retrieve data to be displayed
  • E.g http://localhost:5000/applyFilter
  • Required params in api url:
    • filterValues, page, limit
    • filterValues format after user clicks on apply filter button will be in an object for example:
      • filterValues: { Name: '', Country: [ 'N/A' ] }
    • page is the page number, will be passed in after applying filter
    • limit is the number of items displayed in a page, will be passed in after applying filter
  • Expected output of api is (response.data):
    • data: array of objects (table data)
    • totalPages: Number (number of pages in pagination)
    • Example:
         {
            "data": [
                {
                    "_id": "6614b7c2199743da24dc1a5b",
                    "Country": "N/A",
                    "Number": 2,
                    "Dateline": "2024-01-06T12:30:00.000+00:00",
                    "Name": "Peter"
                },
                {
                    "_id": "6614b7c2199743da24dc1a5d",
                    "Country": "N/A",
                    "Number": 86,
                    "Dateline": "2024-02-06T12:30:00.000+00:00",
                    "Optional": false,
                    "Name": "Aimee"
                },
                {
                    "_id": "6614b7c2199743da24dc1a5e",
                    "Country": "N/A",
                    "Number": 98,
                    "Dateline": "2022-04-06T12:30:00.000+00:00",
                    "Optional": false,
                    "Name": "Chloe"
                },
                {
                    "_id": "661746bb6d176f3a79b9d64c",
                    "Country": "N/A",
                    "Number": 86,
                    "Dateline": "2024-02-06T12:30:00.000+00:00",
                    "Optional": false,
                    "Name": "Marcus"
                },
                {
                    "_id": "6626050a64812c92fa97c5b5",
                    "Country": "N/A",
                    "Number": 86,
                    "Dateline": "2024-02-06T12:30:00.000+00:00",
                    "Optional": false,
                    "Name": "Sarah"
                }
            ],
            "totalPages": 1
        }
  • Example of how api may look like (collectionName is not required to be in req.query):
  router.get("/applyFilter", async (req, res) => {
  try {
    let { filterValues, collectionName } = req.query;
    let { page, limit, sortField, sortDirection } = req.query;
    console.log(req.query);
    if (page === undefined) {
      page = 1;
    }
    if (limit === undefined) {
      limit = 5;
    }
    let skip = (page - 1) * limit;
    // Check if the model already exists
    const Model = require(`./models/${collectionName}`);
    // Construct the filter query based on the filterValues
    const filterQuery = {};

    // Check if filterNumber is a valid number
    if (filterValues) {
      if (!isNaN(parseInt(filterValues.Number))) {
        // Use filterNumber in your filter logic
        filterValues.Number = parseInt(filterValues.Number);
      } else {
        // Handle the case where filterNumber is not a valid number
      }
    } else {
      filterValues = {};
    }
    // Iterate over the filterValues object
    for (const [key, value] of Object.entries(filterValues)) {
      // Check if the value is empty or null
      if (value !== "" && value !== null) {
        // For each filter category
        switch (typeof value) {
          case "string":
            if (value.includes(",")) {
              // Construct regex pattern to match both scenarios as a string
              const regexPattern = `^(${value
                .split(",")
                .map((v) => v.trim())
                .join("|")})$`;

              // Use the regex pattern in the MongoDB query
              filterQuery[key] = { $regex: regexPattern, $options: "i" };
            } else {
              if (value === "false" || value === "true") {
                filterQuery[key] = value;
              } else {
                // Otherwise, construct the regex pattern
                const regex = new RegExp(value, "i");
                filterQuery[key] = { $regex: regex };
              }
            }
            break;
          case "number":
            // For single value filters, directly add to filterQuery
            filterQuery[key] = value;
            break;
          case "object":
            // For range filters, construct $gte and $lte conditions
            if ("start" in value && "end" in value) {
              // Handle range filters
              if (
                value !== null &&
                value !== "" &&
                value.start !== "" &&
                value.end !== ""
              ) {
                if (isNaN(value.start) || isNaN(value.end)) {
                  filterQuery[key] = {
                    $gte: value.start + "T00:00:00",
                    $lte: value.end + "T23:59:59",
                  };
                } else {
                  filterQuery[key] = { $gte: value.start, $lte: value.end };
                }
              }
            } else {
              // Handle other object types
              filterQuery[key] = value;
            }
            break;
          default:
            // Handle other filter types if necessary
            break;
        }
      }
    }
    const totalCount = await Model.countDocuments(filterQuery);
    console.log(skip);
    console.log(totalCount);
    if (skip >= totalCount) {
      skip = 0;
    }
    // Calculate the total number of pages
    const totalPages = Math.ceil(totalCount / limit);
    // Perform the query with filterQuery and pagination options
    const data = await Model.find(filterQuery)
      .sort(sortField ? { [sortField]: sortDirection === "asc" ? 1 : -1 } : {})
      .skip(skip) // Skip documents
      .limit(limit); // Limit the number of documents

    // Send the filtered data and total pages as response
    res.json({ data, totalPages });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
});

3 collectionName

  • Optional
  • Used if api url requires in req.query

4 theme

  • Optional
  • Default theme is light
  • Available themes: light, blue, dark, pink, sky, green, purple, red, yellow

Example Use of Library

import React from 'react'
import UseCustomFilters from 'custom-filter-react'
import config from "../config";
const { backendUrl } = config;
const testLibrary = () => {
  const filterConfigurations = [
    {
      type: "Dropdown",
      placeholder: "Select Category",
      multiSelect: true,
      field: "Country",
      dropdownStyles: { border: "1px solid #ccc" },
      className: "custom-dropdown",
      url: `http://${backendUrl}/getFieldOptions`,
    },
    {
      type: "NumberInput",
      range: true,
      field: "Number",
      placeholder: "Number",
    },
    {
      type: "DateInput",
      range: true,
      field: "Dateline",
      formatStyle: "large",
      firstPlaceHolder: "Start Date",
      secondPlaceHolder: "End Date",
      firstLabel: "Select Date Range",
      button: true,
    },
    {
      type: "CheckboxInput",
      field: "Optional",
      label: "Optional",
      color: "success",
    },
    {
      type: "TextField",
      field: "Name",
      placeholder: "Name",
      width: "30",
    },
  ];
  return (
    <div>
      <UseCustomFilters filterConfigurations={filterConfigurations} url={`http://${backendUrl}/applyFilter`} theme={"red"} />
    </div>
  )
}

export default testLibrary

Required fields for each type of filter

  1. Number input | Props | Value | Required | | -------- | ------- | ------- | | field | field in the database to be filtered | yes |
    | range | true/false | no | | width | number | no | | size | sm/md/lg | no | | placeholder | String | no | | firstPlaceHolder | String | no | | secondPlaceHolder | String | no |

  2. Date input | Props | Value | Required | | -------- | ------- | ------- | | field | field in the database to be filtered | yes |
    | range | true/false | no | | width | number | no | | formatStyle | small/medium/large | no | | placeholder | String | no | | firstPlaceHolder | String | no | | secondPlaceHolder | String | no | | label | String | no | | firstLabel | String | no | | secondLabel | String | no |

  3. Dropdown | Props | Value | Required | | -------- | ------- | ------- | | field | field in the database to be filtered | yes |
    | url | String | yes | | collectionName | String | no if url route already has collection name determined | | fontSize | Number | no | | placeholder | String | no | | width | Number | no | | multiSelect | true/false | no | | className | String | no | | color | String | no |

  4. Checkbox input | Props | Value | Required | | -------- | ------- | ------- | | field | field in the database to be filtered | yes |
    | defaultChecked | true/false | no | | size | small/medium/large | no | | label | String | no | | color | String | no |

  5. Textfield input | Props | Value | Required | | -------- | ------- | ------- | | field | field in the database to be filtered | yes |
    | width | number | no | | size | sm/md/lg | no | | placeholder | String | no |