finish functionality of number filter
Also refactor filter logic
This commit is contained in:
parent
5b6cf900e0
commit
09e2db558d
3 changed files with 95 additions and 38 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { type ChangeEventHandler } from 'react';
|
||||
import React, { useState, type ChangeEventHandler, useEffect } from 'react';
|
||||
|
||||
interface Props {
|
||||
onChange: (value: string | string[] | number | number[] | null) => void;
|
||||
|
|
@ -6,20 +6,39 @@ interface Props {
|
|||
}
|
||||
|
||||
export default function NumberInput({ keyData, onChange }: Props): JSX.Element {
|
||||
const onSelectChange: ChangeEventHandler<HTMLInputElement> = ({
|
||||
target,
|
||||
}): void => {
|
||||
const value = parseInt(target.value);
|
||||
onChange(isNaN(value) ? null : value);
|
||||
};
|
||||
const [value, setValue] = useState<string>('');
|
||||
const [operator, setOperator] = useState<string>('=');
|
||||
|
||||
useEffect(() => {
|
||||
onChange([operator, value === '' ? null : parseFloat(value)]);
|
||||
}, [value, operator]);
|
||||
|
||||
return (
|
||||
<input
|
||||
name={`number-input-${keyData}`}
|
||||
id="foo"
|
||||
type="number"
|
||||
placeholder="1"
|
||||
onChange={onSelectChange}
|
||||
/>
|
||||
<div className="hstack">
|
||||
<select
|
||||
name={`number-select-${keyData}`}
|
||||
id={`number-select-${keyData}`}
|
||||
onChange={({ target }) => {
|
||||
setOperator(target.value);
|
||||
}}
|
||||
>
|
||||
<option value="=" selected>
|
||||
=
|
||||
</option>
|
||||
<option value=">">{'>'}</option>
|
||||
<option value="<">{'<'}</option>
|
||||
<option value=">=">{'>='}</option>
|
||||
<option value="<=">{'<='}</option>
|
||||
</select>
|
||||
<input
|
||||
name={`number-input-${keyData}`}
|
||||
id="foo"
|
||||
type="number"
|
||||
placeholder="1"
|
||||
onChange={({ target }) => {
|
||||
setValue(target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,60 @@
|
|||
import { HeaderType } from '../Table.tsx';
|
||||
|
||||
export { default as SelectInput } from './SelectInput.tsx';
|
||||
export { default as NumberInput } from './NumberInput.tsx';
|
||||
|
||||
export type DataItem = Record<string, any>;
|
||||
|
||||
export interface Filter {
|
||||
type: HeaderType;
|
||||
value: string | string[] | number | number[];
|
||||
}
|
||||
|
||||
const filterString = (value: Filter['value'], data: any): boolean => {
|
||||
return data.search(value) !== -1;
|
||||
};
|
||||
const filterNumber = (value: Filter['value'], data: any): boolean => {
|
||||
const [operator, numberValue] = value;
|
||||
|
||||
if (numberValue === null) return true;
|
||||
|
||||
switch (operator) {
|
||||
case '=':
|
||||
return data === numberValue;
|
||||
case '<':
|
||||
return data < numberValue;
|
||||
case '>':
|
||||
return data > numberValue;
|
||||
case '<=':
|
||||
return data <= numberValue;
|
||||
case '>=':
|
||||
return data >= numberValue;
|
||||
|
||||
default:
|
||||
return data === numberValue;
|
||||
}
|
||||
};
|
||||
const filterSelect = (value: Filter['value'], data: any): boolean => {
|
||||
return data === value;
|
||||
};
|
||||
const filterMultiple = (value: Filter['value'], data: any): boolean => {
|
||||
if (typeof value === 'string') {
|
||||
return data.includes(value);
|
||||
}
|
||||
return value.every((filter: string) => data.includes(filter));
|
||||
};
|
||||
|
||||
export const resolveFilterByType = (filter: Filter, data: any): boolean => {
|
||||
switch (filter.type) {
|
||||
case HeaderType.String:
|
||||
return filterString(filter.value, data);
|
||||
case HeaderType.Number:
|
||||
return filterNumber(filter.value, data);
|
||||
case HeaderType.Select:
|
||||
return filterSelect(filter.value, data);
|
||||
case HeaderType.Multiple:
|
||||
return filterMultiple(filter.value, data);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import usePagination, { Offset } from 'src/hooks/usePagination';
|
||||
import { SelectInput, NumberInput } from './Inputs';
|
||||
import {
|
||||
SelectInput,
|
||||
NumberInput,
|
||||
resolveFilterByType,
|
||||
type Filter,
|
||||
} from './Inputs';
|
||||
|
||||
export type DataItem = Record<string, any>;
|
||||
|
||||
|
|
@ -24,32 +29,9 @@ interface Props {
|
|||
headers: Header[];
|
||||
}
|
||||
|
||||
interface Filter {
|
||||
type: HeaderType;
|
||||
value: string | string[] | number | number[];
|
||||
}
|
||||
|
||||
export default function Table({ data, headers }: Props): JSX.Element {
|
||||
const [filters, setFilters] = useState<Record<string, Filter>>({});
|
||||
|
||||
const resolveFilterByType = (filter: Filter, data: any): boolean => {
|
||||
switch (filter.type) {
|
||||
case HeaderType.String:
|
||||
return data.search(filter.value) !== -1;
|
||||
case HeaderType.Number:
|
||||
return data === filter.value;
|
||||
case HeaderType.Select:
|
||||
return data === filter.value;
|
||||
case HeaderType.Multiple:
|
||||
if (typeof filter.value === 'string') {
|
||||
return data.includes(filter.value);
|
||||
}
|
||||
return filter.value.every((filter: string) => data.includes(filter));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
return data.filter((item) => {
|
||||
return Object.entries(filters).every(([key, filter]) =>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue