finish functionality of number filter

Also refactor filter logic
This commit is contained in:
Alexander Navarro 2023-10-07 13:03:35 -03:00
parent 5b6cf900e0
commit 09e2db558d
3 changed files with 95 additions and 38 deletions

View file

@ -1,4 +1,4 @@
import React, { type ChangeEventHandler } from 'react'; import React, { useState, type ChangeEventHandler, useEffect } from 'react';
interface Props { interface Props {
onChange: (value: string | string[] | number | number[] | null) => void; onChange: (value: string | string[] | number | number[] | null) => void;
@ -6,20 +6,39 @@ interface Props {
} }
export default function NumberInput({ keyData, onChange }: Props): JSX.Element { export default function NumberInput({ keyData, onChange }: Props): JSX.Element {
const onSelectChange: ChangeEventHandler<HTMLInputElement> = ({ const [value, setValue] = useState<string>('');
target, const [operator, setOperator] = useState<string>('=');
}): void => {
const value = parseInt(target.value); useEffect(() => {
onChange(isNaN(value) ? null : value); onChange([operator, value === '' ? null : parseFloat(value)]);
}; }, [value, operator]);
return ( return (
<input <div className="hstack">
name={`number-input-${keyData}`} <select
id="foo" name={`number-select-${keyData}`}
type="number" id={`number-select-${keyData}`}
placeholder="1" onChange={({ target }) => {
onChange={onSelectChange} 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>
); );
} }

View file

@ -1,4 +1,60 @@
import { HeaderType } from '../Table.tsx';
export { default as SelectInput } from './SelectInput.tsx'; export { default as SelectInput } from './SelectInput.tsx';
export { default as NumberInput } from './NumberInput.tsx'; export { default as NumberInput } from './NumberInput.tsx';
export type DataItem = Record<string, any>; 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;
};

View file

@ -1,6 +1,11 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import usePagination, { Offset } from 'src/hooks/usePagination'; 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>; export type DataItem = Record<string, any>;
@ -24,32 +29,9 @@ interface Props {
headers: Header[]; headers: Header[];
} }
interface Filter {
type: HeaderType;
value: string | string[] | number | number[];
}
export default function Table({ data, headers }: Props): JSX.Element { export default function Table({ data, headers }: Props): JSX.Element {
const [filters, setFilters] = useState<Record<string, Filter>>({}); 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(() => { const filteredItems = useMemo(() => {
return data.filter((item) => { return data.filter((item) => {
return Object.entries(filters).every(([key, filter]) => return Object.entries(filters).every(([key, filter]) =>