fun joker
fun joker

Reputation: 1727

How to create date filter in javascript?

I have JSON data which has structure as follows:

data = [
{
    "id": 100,
    "floorplans": [
        {
            "bhk": 1,
            ...some other fields
        },
        {
            "bhk": 3,
            ...some other fields
        },
        {
            "bhk": 2,
            ...some other fields
        }
    ],
    "possession_date": "2016-08-21"
},
{
    "id": 200,
    "floorplans": [
        {
            "bhk": 1.5,
            ...some other fields
        },
        {
            "bhk": 1,
            ...some other fields
        },
        {
            "bhk": 2.5,
            ...some other fields    
        }
    ],
    "possession_date": "2017-08-21"
},
{
    "id": 300,
    "floorplans": [
        {
            "bhk": 1,
            ...some other fields
        },
        {
            "bhk": 4,
            ...some other fields
        },
        {
            "bhk": 2,
            ...some other fields
        }
    ],
    "possession_date": "2018-08-21"
}]

Now above data is getting stored inside filterOptions array. Now filterOptions example:

filterOptions ["Ready", 2, 4, 1] -> this means filter all the data which has 2,4,1 BHK included and also that data which has possession_date < current date

filterOptions ["Under construction", 3] -> this means filter all the data which has 3 BHK included and also that data which has possession_date > current date

So I have the code as follows:

Note: I am using .slice() because I am comparing date of form YYYY-MM-DD.

function checkStatus(options, date) {
  console.log("Status: ", options)
  const currentTime = moment().format();
  let d1 = Date.parse(currentTime.slice(0,10));
  let d2 = Date.parse(date.slice(0,10));

  if(options.includes("Ready")){
    if(d1 > d2)
      return true;
  } else if(options.includes("Under construction")){
    if(d1 < d2)
      return true;
  }

}

 var display_filtered_projects = data.filter(
        (item) => item.floorplans.some(val => filterOptions.includes(val.bhk))
        && checkStatus(filterOptions, item.possession_date));

    console.log("display_filtered_projects: ", display_filtered_projects);

If I remove checkStatus(filterOptions, item.possession_date) then the filter works perfect but only for BHK type. Now I have to combine it with date how can I do that ?

Upvotes: 0

Views: 1711

Answers (2)

lokhmakov
lokhmakov

Reputation: 207

I recommend to use separate filter lists. (Based on discussion with you in Discord)

import moment               from 'moment'
import React                from 'react'
import ReactDOM             from 'react-dom'


const FIELD_DATE = `possession_date`

const yourMegaListFromStackoverflow = [
  {
    "id": 100,
    "floorplans": [
      {
        "bhk": 1,
      },
      {
        "bhk": 3,
      },
      {
        "bhk": 2,
      }
    ],
    "possession_date": "2016-08-21"
  },
  {
    "id": 200,
    "floorplans": [
      {
        "bhk": 1.5,
      },
      {
        "bhk": 1,
      },
      {
        "bhk": 2.5,
      }
    ],
    "possession_date": "2017-08-21"
  },
  {
    "id": 300,
    "floorplans": [
      {
        "bhk": 1,
      },
      {
        "bhk": 4,
      },
      {
        "bhk": 2,
      }
    ],
    "possession_date": "2018-08-21"
  }
]

const statusType = {
  'READY': `READY`,
  'UNDER_CONSTRUCTION': `UNDER_CONSTRUCTION`,
}

const statusMap = {
  [statusType.READY]: `Ready to move`,
  [statusType.UNDER_CONSTRUCTION]: `Under Construction`,
}

const statusList = Object.keys(statusMap)

const FilterStatus = (props) => {
  const {
    activeList = [],
    onClick,
  } = props

  return statusList.map((name) => (
    <div
      key={name}
      style={{ fontWeight: activeList.includes(name) && `bold` }}
      onClick={() => onClick({ name })}
    >
      {statusMap[name]}
    </div>
  ))
}

const typeType = {
  'UNO': `UNO`,
  'DOS': `DOS`,
  'TRES': `TRES`,
  'TRES_PLUS': `TRES_PLUS`,
}

const typeMap = {
  [typeType.UNO]: `1 BHK`,
  [typeType.DOS]: `2 BHK`,
  [typeType.TRES]: `3 BHK`,
  [typeType.TRES_PLUS]: `3+ BHK`,
}

const typeFilterMap = {
  [typeType.UNO]: (value) => value === 1,
  [typeType.DOS]: (value) => value === 2,
  [typeType.TRES]: (value) => value === 3,
  [typeType.TRES_PLUS]: (value) => value >= 3,
}

const typeList = Object.keys(typeMap)

const FilterType = (props) => {
  const {
    activeList = [],
    onClick,
  } = props

  return typeList.map((name) => (
    <div
      key={name}
      style={{ fontWeight: activeList.includes(name) && `bold` }}
      onClick={() => onClick({ name })}
    >
      {typeMap[name]}
    </div>
  ))
}

const App = () => {
  const [filterStatusList, filterStatusListSet] = React.useState([])
  const [filterTypeList, filterTypeListSet] = React.useState([])

  const onFilterStatusClick = React.useCallback(({ name }) => {
    filterStatusList.includes(name)
      ? filterStatusListSet([])
      : filterStatusListSet([name])
  })

  const onFilterTypeClick = React.useCallback(({ name }) => {
    filterTypeList.includes(name)
      ? filterTypeListSet(filterTypeList.filter((value) => value !== name))
      : filterTypeListSet([...filterTypeList, name])
  })

  const list = React.useMemo(
    () => {
      const now = Date.now()
      return yourMegaListFromStackoverflow.filter((doc) => {
        const date = moment(doc[FIELD_DATE]).format(`x`)

        const isStatusOk = filterStatusList.includes(statusType.READY)
          ? now > date
          : filterStatusList.includes(statusType.UNDER_CONSTRUCTION)
            && now < date

        return isStatusOk
          && doc.floorplans.some(
            ({ bhk }) => filterTypeList.some(
              (name) => typeFilterMap[name](bhk)
            )
          )
      })
    },
    [filterStatusList, filterTypeList]
  )

  return <>
    <FilterStatus
      activeList={filterStatusList}
      onClick={onFilterStatusClick}
    />

    <FilterType
      activeList={filterTypeList}
      onClick={onFilterTypeClick}
    />

    {list.map((doc) => (
      <div key={doc.id}>{doc.id}</div>
    ))}
  </>
}

const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)

Upvotes: 2

Pushkar Adhikari
Pushkar Adhikari

Reputation: 510

you can modify your filter logic to:

let filterData = data.filter(
  a => a.floorplans.some(e => temp.includes(e.bhk))
  && checkStatus(temp[2], a.possession_date)
);
.
.
.
function checkStatus(status, date) {
  if (status === 'Ready') {
    return new Date(date) < Date.now();
  } else {
    return Date.now() < new Date(date);
  }
}

EDIT Assuming you only want to check for 'Ready' in the temp array:

let filterData = data.filter(
  a => a.floorplans.some(e => temp.includes(e.bhk))
  && checkStatus(temp, a.possession_date)
);
.
.
.
function checkStatus(temporaryData, date) {
  if (temporaryData.indexOf('Ready') !== -1) {
    return new Date(date) < Date.now();
  } else {
    return Date.now() < new Date(date);
  }
}

EDIT 2

in the display_filtered_projects.push(x); part, I am not sure if you are expecting y otherwise. The catch here is that if data contains repeated results, they would end up being added repeatedly. I have updated code to use Set to solve this.

var data = [{
    "id": 100,
    "floorplans": [{
        "bhk": 1,
      },
      {
        "bhk": 3,
      },
      {
        "bhk": 2,
      }
    ],
    "possession_date": "2016-08-21"
  },
  {
    "id": 200,
    "floorplans": [{
        "bhk": 1.5,
      },
      {
        "bhk": 1,
      },
      {
        "bhk": 2.5,
      }
    ],
    "possession_date": "2017-08-21"
  },
  {
    "id": 300,
    "floorplans": [{
        "bhk": 1,
      },
      {
        "bhk": 4,
      },
      {
        "bhk": 2,
      }
    ],
    "possession_date": "2018-08-21"
  }
]

var filterOptions = ["Ready", 2];

function checkStatus(options, date) {
  // console.log("Status: ", options)
  let d1 = Date.now();
  let d2 = new Date(date);

  if (options.includes("Ready")) {
    if (d1 > d2)
      return true;
  } else if (options.includes("Under construction")) {
    if (d1 < d2)
      return true;
  } else {
    return true;
  }

}
var display_filtered_projects = new Set();

data.filter(
  (item) => checkStatus(filterOptions, item.possession_date)
).forEach(x => x.floorplans.forEach(y => {
  if (filterOptions.includes(y.bhk)) {
    display_filtered_projects.add(x);
  }
}));

console.log("display_filtered_projects: ", Array.from(display_filtered_projects));

The additional problem here is that your date logic which I have reused would return nothing if the project status wasn't part of your input. So maybe in that case, you just want to return true for all. I've updated the code accordingly.

Upvotes: 2

Related Questions