iTwin / iTwinUI-react

A react component library for iTwinUI.
https://github.com/iTwin/iTwinUI
Other
84 stars 23 forks source link

Table date filter not working #147

Closed klopez213 closed 3 years ago

klopez213 commented 3 years ago

Environment

Code Sandbox

Link to a minimal repro: https://codesandbox.io/s/table-datefilter-zf4hq

Steps to reproduce

  1. Filter the Date column that should return results.

Actual behavior

Valid date filter doesn't return results.

Expected behavior

Results should be returned with valid date filters.

Additional information

The sample code I have in the code sandbox is similar to how I have it in our code. Not sure if it's because of the dates (e.g. "2021-03-08T15:13:24.62") that I have don't have the timezone and I have to format it in the Cell.

mayank99 commented 3 years ago

Thanks for the issue. I tried debugging a little bit, and it seems you're right: it is because your data uses strings. If I wrap the dates in your data with new Date(), the filter starts to work.

I then looked at our "Story" (and I'm assuming that's where you copied the code from), and it seems that's where the real bug is. It doesn't show that we expect the data to use Date objects.

Here's what it should look like: https://github.com/iTwin/iTwinUI-react/blob/e99e4599704a29c6f73c3e402e4368426a9b294b/stories/core/Table.stories.tsx#L446-L468

klopez213 commented 3 years ago

Problem though is that the data is coming from the server as is. That's why I had to format using the Cell.

mayank99 commented 3 years ago

In that case, you can pass a custom function to the filter field in your column.

Here's a modified version of our betweenDate filter:

const betweenDate = <T extends Record<string, unknown>>(
  rows: Row<T>[],
  ids: IdType<T>[],
  filterValue: [Date?, Date?] | undefined,
) => {
  const [min, max] = filterValue || [];

  const MAX_DATE_VALUE = 8640000000000000;
  const isValidDate = (date: Date | undefined) => !!date && !isNaN(date.valueOf());
  const minValue = (isValidDate(min) ? min : new Date(-MAX_DATE_VALUE)) as Date;
  const maxValue = (isValidDate(max) ? max : new Date(MAX_DATE_VALUE)) as Date;

  return rows.filter((row) => {
    return ids.some((id) => {
      const rowValue = new Date(row.values[id]); // converting to Date object here
      return (
        rowValue.valueOf() >= minValue.valueOf() &&
        rowValue.valueOf() <= maxValue.valueOf()
      );
    });
  });
};

I forked your sandbox and got it to work (missing memoization though): https://codesandbox.io/s/table-datefilter-forked-csq41?file=/src/App.js:1801-1825

Does that solve your problem?

klopez213 commented 3 years ago

It does, the custom filter function works. Thanks! Does that mean that this isn't going to be fixed in the betweenDate filter?

bentleyvk commented 3 years ago

Hi, there is a simpler fix to your issue. Just add this to your column object: accessor: (rowData) => new Date(rowData.date) Link to codesandblox: https://codesandbox.io/s/table-datefilter-forked-2jc49?file=/src/App.js:944-990

klopez213 commented 3 years ago

Thank you. That worked beautifully.