Skip to content

Commit 5fc79ae

Browse files
Feat(table): add min max limit for number range filter (#1725)
* feat(table): add min max limit for number range filter * feat(table): implement range filtering with min/max constraints in TableRangeFilter * feat(table): update age range filter maximum limit to 100
1 parent 15e3f6f commit 5fc79ae

4 files changed

Lines changed: 71 additions & 2 deletions

File tree

apps/demo/src/Views/Ui/components/Table/Table.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ export const TableDemo = () => {
5555
enableSorting: true,
5656
filterPlaceholder: `${t("table.placeholder.min")},${t("table.placeholder.max")}`,
5757
header: "Age",
58+
meta: {
59+
rangeFilterMax: 100,
60+
rangeFilterMin: 1,
61+
},
5862
},
5963
{
6064
accessorKey: "city",

packages/ui/src/FormWidgets/DebouncedInput/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { IInputProperties, Input } from "../Input";
1212
export interface DebouncedInputProperties extends IInputProperties {
1313
debounceTime?: number;
1414
onInputChange: (value: number | readonly string[] | string) => void;
15+
sanitizeValue?: (value: string) => string;
1516
}
1617

1718
export const DebouncedInput = forwardRef<
@@ -24,6 +25,7 @@ export const DebouncedInput = forwardRef<
2425
debounceTime = 500,
2526
defaultValue = "",
2627
onInputChange,
28+
sanitizeValue,
2729
type = "text",
2830
...inputProperties
2931
},
@@ -50,7 +52,13 @@ export const DebouncedInput = forwardRef<
5052
}, [debouncedValue]);
5153

5254
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
53-
setInputValue(event.target.value);
55+
let rawValue = event.target.value;
56+
57+
if (sanitizeValue) {
58+
rawValue = sanitizeValue(rawValue);
59+
}
60+
61+
setInputValue(rawValue);
5462
};
5563

5664
return (

packages/ui/src/Table/TableRangeFilter.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,24 @@ export const TableRangeFilter = <TData,>({
2424
? [...filterValue]
2525
: [undefined, undefined];
2626

27-
currentFilter[index] = value !== "" ? Number(value) : undefined;
27+
const numericValue = value !== "" ? Number(value) : undefined;
28+
29+
if (numericValue !== undefined) {
30+
const { rangeFilterMax, rangeFilterMin } = column.columnDef.meta ?? {};
31+
32+
if (rangeFilterMin !== undefined && numericValue < rangeFilterMin) {
33+
currentFilter[index] = rangeFilterMin;
34+
} else if (
35+
rangeFilterMax !== undefined &&
36+
numericValue > rangeFilterMax
37+
) {
38+
currentFilter[index] = rangeFilterMax;
39+
} else {
40+
currentFilter[index] = numericValue;
41+
}
42+
} else {
43+
currentFilter[index] = undefined;
44+
}
2845

2946
const isFilterActive = currentFilter.some(
3047
(filterInput) => filterInput !== undefined,
@@ -35,6 +52,38 @@ export const TableRangeFilter = <TData,>({
3552

3653
const filterValue = column.getFilterValue() as (number | undefined)[];
3754
const key = column.id || String(column.columnDef.accessorKey);
55+
const meta = column.columnDef.meta;
56+
57+
const clampRangeValue = (value: string): string => {
58+
if (
59+
meta?.rangeFilterMin === undefined &&
60+
meta?.rangeFilterMax === undefined
61+
) {
62+
return value;
63+
}
64+
65+
const numericValue = Number(value);
66+
67+
if (Number.isNaN(numericValue)) {
68+
return value;
69+
}
70+
71+
if (
72+
meta.rangeFilterMin !== undefined &&
73+
numericValue < meta.rangeFilterMin
74+
) {
75+
return String(meta.rangeFilterMin);
76+
}
77+
78+
if (
79+
meta.rangeFilterMax !== undefined &&
80+
numericValue > meta.rangeFilterMax
81+
) {
82+
return String(meta.rangeFilterMax);
83+
}
84+
85+
return value;
86+
};
3887

3988
return (
4089
<div className="number-range-filter">
@@ -45,12 +94,15 @@ export const TableRangeFilter = <TData,>({
4594
? filterValue[0]
4695
: ""
4796
}
97+
max={meta?.rangeFilterMax}
98+
min={meta?.rangeFilterMin}
4899
name={`range-start-${key}`}
49100
onInputChange={(value) => updateRangeFilter(column, 0, value)}
50101
placeholder={
51102
column.columnDef.filterPlaceholder?.split(",")[0] ??
52103
column.columnDef.filterPlaceholder
53104
}
105+
sanitizeValue={clampRangeValue}
54106
type="number"
55107
/>
56108
<DebouncedInput
@@ -60,12 +112,15 @@ export const TableRangeFilter = <TData,>({
60112
? filterValue[1]
61113
: ""
62114
}
115+
max={meta?.rangeFilterMax}
116+
min={meta?.rangeFilterMin}
63117
name={`range-end-${key}`}
64118
onInputChange={(value) => updateRangeFilter(column, 1, value)}
65119
placeholder={
66120
column.columnDef.filterPlaceholder?.split(",")[1] ??
67121
column.columnDef.filterPlaceholder
68122
}
123+
sanitizeValue={clampRangeValue}
69124
type="number"
70125
/>
71126
</div>

packages/ui/src/Table/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ declare module "@tanstack/react-table" {
4646
interface ColumnMeta<TData extends RowData, TValue> {
4747
filterOptions?: FilterOption[];
4848
filterVariant?: TFilterVariant;
49+
rangeFilterMax?: number;
50+
rangeFilterMin?: number;
4951
serverFilterFn?: TFilterFn;
5052
}
5153
}

0 commit comments

Comments
 (0)