@ram_28/kf-ai-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +840 -0
- package/dist/api/client.d.ts +78 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/datetime.d.ts +21 -0
- package/dist/api/datetime.d.ts.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/metadata.d.ts +75 -0
- package/dist/api/metadata.d.ts.map +1 -0
- package/dist/components/hooks/index.d.ts +8 -0
- package/dist/components/hooks/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/index.d.ts +5 -0
- package/dist/components/hooks/useFilter/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts +33 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/types.d.ts +137 -0
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts +3 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts +38 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +71 -0
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/index.d.ts +6 -0
- package/dist/components/hooks/useForm/index.d.ts.map +1 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts +88 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts +29 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/types.d.ts +412 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +3 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts +99 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/context.d.ts +4 -0
- package/dist/components/hooks/useKanban/context.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts +27 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/index.d.ts +6 -0
- package/dist/components/hooks/useKanban/index.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/types.d.ts +438 -0
- package/dist/components/hooks/useKanban/types.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts +3 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts +62 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +3 -0
- package/dist/components/hooks/useTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useTable/types.d.ts +107 -0
- package/dist/components/hooks/useTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useTable/useTable.d.ts +8 -0
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/kanban/Kanban.d.ts +12 -0
- package/dist/components/ui/kanban/Kanban.d.ts.map +1 -0
- package/dist/components/ui/kanban/index.d.ts +2 -0
- package/dist/components/ui/kanban/index.d.ts.map +1 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +6522 -0
- package/dist/types/base-fields.d.ts +182 -0
- package/dist/types/base-fields.d.ts.map +1 -0
- package/dist/types/common.d.ts +238 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +7 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/formatting.d.ts +52 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/sdk/api/client.ts +447 -0
- package/sdk/api/datetime.ts +33 -0
- package/sdk/api/index.ts +61 -0
- package/sdk/api/metadata.ts +148 -0
- package/sdk/components/hooks/index.ts +34 -0
- package/sdk/components/hooks/useFilter/index.ts +37 -0
- package/sdk/components/hooks/useFilter/payloadBuilder.utils.ts +298 -0
- package/sdk/components/hooks/useFilter/types.ts +158 -0
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +497 -0
- package/sdk/components/hooks/useFilter/useFilter.ts +494 -0
- package/sdk/components/hooks/useFilter/validation.utils.ts +401 -0
- package/sdk/components/hooks/useForm/apiClient.ts +441 -0
- package/sdk/components/hooks/useForm/expressionValidator.utils.ts +444 -0
- package/sdk/components/hooks/useForm/index.ts +64 -0
- package/sdk/components/hooks/useForm/optimizedExpressionValidator.utils.ts +482 -0
- package/sdk/components/hooks/useForm/ruleClassifier.utils.ts +424 -0
- package/sdk/components/hooks/useForm/schemaParser.utils.ts +519 -0
- package/sdk/components/hooks/useForm/types.ts +630 -0
- package/sdk/components/hooks/useForm/useForm.llm.txt +340 -0
- package/sdk/components/hooks/useForm/useForm.ts +821 -0
- package/sdk/components/hooks/useKanban/apiClient.ts +494 -0
- package/sdk/components/hooks/useKanban/context.ts +14 -0
- package/sdk/components/hooks/useKanban/dragDropManager.ts +529 -0
- package/sdk/components/hooks/useKanban/index.ts +63 -0
- package/sdk/components/hooks/useKanban/types.ts +606 -0
- package/sdk/components/hooks/useKanban/useKanban.llm.txt +482 -0
- package/sdk/components/hooks/useKanban/useKanban.ts +725 -0
- package/sdk/components/hooks/useKanban/useKanbanSimple.ts +389 -0
- package/sdk/components/hooks/useTable/index.ts +5 -0
- package/sdk/components/hooks/useTable/types.ts +154 -0
- package/sdk/components/hooks/useTable/useTable.llm.txt +344 -0
- package/sdk/components/hooks/useTable/useTable.ts +413 -0
- package/sdk/components/index.ts +15 -0
- package/sdk/components/ui/index.ts +2 -0
- package/sdk/components/ui/kanban/Kanban.tsx +134 -0
- package/sdk/components/ui/kanban/index.ts +11 -0
- package/sdk/index.ts +13 -0
- package/sdk/types/base-fields.ts +221 -0
- package/sdk/types/common.ts +306 -0
- package/sdk/types/index.ts +5 -0
- package/sdk/utils/cn.ts +10 -0
- package/sdk/utils/formatting.ts +212 -0
- package/sdk/utils/index.ts +5 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
# useFilter Hook - LLM Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `useFilter` hook is a React hook for managing filter conditions with:
|
|
6
|
+
- Type-safe filter condition management
|
|
7
|
+
- Support for simple conditions and nested logical groups
|
|
8
|
+
- Automatic validation
|
|
9
|
+
- API payload generation
|
|
10
|
+
- State import/export
|
|
11
|
+
- Integrated with useTable hook
|
|
12
|
+
|
|
13
|
+
## Import
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { useFilter } from "kf-ai-sdk";
|
|
17
|
+
// Or use through useTable's filter property
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic Usage
|
|
21
|
+
|
|
22
|
+
### Standalone Usage
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const filter = useFilter<ProductType>({
|
|
26
|
+
initialLogicalOperator: "And",
|
|
27
|
+
fieldDefinitions: {
|
|
28
|
+
Price: {
|
|
29
|
+
type: "number",
|
|
30
|
+
allowedOperators: ["EQ", "GT", "LT", "GTE", "LTE", "Between"],
|
|
31
|
+
},
|
|
32
|
+
Category: {
|
|
33
|
+
type: "string",
|
|
34
|
+
allowedOperators: ["EQ", "NE", "Contains"],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
onValidationError: (errors) => console.log(errors),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Add a condition
|
|
41
|
+
const id = filter.addCondition({
|
|
42
|
+
lhsField: "Price",
|
|
43
|
+
operator: "GT",
|
|
44
|
+
rhsValue: 100,
|
|
45
|
+
rhsType: "Constant",
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Through useTable
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const table = useTable<ProductType>({
|
|
53
|
+
source: "BDO_Products",
|
|
54
|
+
columns: [...],
|
|
55
|
+
enableFiltering: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Use table.filter for all filter operations
|
|
59
|
+
table.filter.addCondition({
|
|
60
|
+
lhsField: "Category",
|
|
61
|
+
operator: "EQ",
|
|
62
|
+
rhsValue: "Electronics",
|
|
63
|
+
rhsType: "Constant",
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuration Options
|
|
68
|
+
|
|
69
|
+
### UseFilterOptions<T>
|
|
70
|
+
|
|
71
|
+
| Property | Type | Required | Default | Description |
|
|
72
|
+
|----------|------|----------|---------|-------------|
|
|
73
|
+
| `initialConditions` | `FilterConditionWithId[]` | No | `[]` | Initial filter conditions |
|
|
74
|
+
| `initialLogicalOperator` | `LogicalOperator` | No | `"And"` | Initial logical operator |
|
|
75
|
+
| `fieldDefinitions` | `Record<keyof T, FieldDefinition>` | No | - | Field definitions for validation |
|
|
76
|
+
| `validateOnChange` | `boolean` | No | `true` | Validate conditions on change |
|
|
77
|
+
| `onConditionAdd` | `(condition) => void` | No | - | Callback when condition added |
|
|
78
|
+
| `onConditionUpdate` | `(condition) => void` | No | - | Callback when condition updated |
|
|
79
|
+
| `onConditionRemove` | `(conditionId) => void` | No | - | Callback when condition removed |
|
|
80
|
+
| `onValidationError` | `(errors) => void` | No | - | Callback for validation errors |
|
|
81
|
+
|
|
82
|
+
### FieldDefinition
|
|
83
|
+
|
|
84
|
+
| Property | Type | Description |
|
|
85
|
+
|----------|------|-------------|
|
|
86
|
+
| `type` | `'string' \| 'number' \| 'date' \| 'boolean' \| 'currency' \| 'select'` | Field data type |
|
|
87
|
+
| `allowedOperators` | `FilterOperator[]` | Operators allowed for this field |
|
|
88
|
+
| `validateValue` | `(value, operator) => ValidationResult` | Custom validation function |
|
|
89
|
+
| `transformValue` | `(value) => any` | Value transformation function |
|
|
90
|
+
| `selectOptions` | `Array<{label, value}>` | Options for select fields |
|
|
91
|
+
|
|
92
|
+
## Return Value
|
|
93
|
+
|
|
94
|
+
### UseFilterReturn<T>
|
|
95
|
+
|
|
96
|
+
#### Current State
|
|
97
|
+
| Property | Type | Description |
|
|
98
|
+
|----------|------|-------------|
|
|
99
|
+
| `conditions` | `FilterConditionWithId[]` | Current filter conditions |
|
|
100
|
+
| `logicalOperator` | `LogicalOperator` | Current logical operator ("And" \| "Or") |
|
|
101
|
+
| `filterPayload` | `Filter \| undefined` | SDK-formatted filter for API |
|
|
102
|
+
| `isValid` | `boolean` | All conditions are valid |
|
|
103
|
+
| `validationErrors` | `ValidationError[]` | Current validation errors |
|
|
104
|
+
|
|
105
|
+
#### Condition Management
|
|
106
|
+
| Property | Type | Description |
|
|
107
|
+
|----------|------|-------------|
|
|
108
|
+
| `addCondition` | `(condition) => string` | Add condition, returns ID |
|
|
109
|
+
| `updateCondition` | `(id, updates) => boolean` | Update condition |
|
|
110
|
+
| `removeCondition` | `(id) => boolean` | Remove condition |
|
|
111
|
+
| `clearConditions` | `() => void` | Clear all conditions |
|
|
112
|
+
| `getCondition` | `(id) => FilterConditionWithId` | Get specific condition |
|
|
113
|
+
|
|
114
|
+
#### Logical Operator
|
|
115
|
+
| Property | Type | Description |
|
|
116
|
+
|----------|------|-------------|
|
|
117
|
+
| `setLogicalOperator` | `(operator) => void` | Set logical operator |
|
|
118
|
+
|
|
119
|
+
#### Bulk Operations
|
|
120
|
+
| Property | Type | Description |
|
|
121
|
+
|----------|------|-------------|
|
|
122
|
+
| `setConditions` | `(conditions) => void` | Replace all conditions |
|
|
123
|
+
| `replaceCondition` | `(id, newCondition) => boolean` | Replace specific condition |
|
|
124
|
+
|
|
125
|
+
#### Validation
|
|
126
|
+
| Property | Type | Description |
|
|
127
|
+
|----------|------|-------------|
|
|
128
|
+
| `validateCondition` | `(condition) => ValidationResult` | Validate single condition |
|
|
129
|
+
| `validateAllConditions` | `() => ValidationResult` | Validate all conditions |
|
|
130
|
+
|
|
131
|
+
#### State Management
|
|
132
|
+
| Property | Type | Description |
|
|
133
|
+
|----------|------|-------------|
|
|
134
|
+
| `exportState` | `() => FilterState` | Export current state |
|
|
135
|
+
| `importState` | `(state) => void` | Import state |
|
|
136
|
+
| `resetToInitial` | `() => void` | Reset to initial state |
|
|
137
|
+
|
|
138
|
+
#### Utilities
|
|
139
|
+
| Property | Type | Description |
|
|
140
|
+
|----------|------|-------------|
|
|
141
|
+
| `getConditionCount` | `() => number` | Get number of conditions |
|
|
142
|
+
| `hasConditions` | `boolean` | Whether any conditions exist |
|
|
143
|
+
| `canAddCondition` | `boolean` | Whether more can be added (always true) |
|
|
144
|
+
|
|
145
|
+
## Filter Condition Types
|
|
146
|
+
|
|
147
|
+
### FilterConditionWithId
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface FilterConditionWithId {
|
|
151
|
+
id: string; // Unique identifier
|
|
152
|
+
operator: FilterOperator | LogicalOperator;
|
|
153
|
+
lhsField?: string; // Field name (for condition operators)
|
|
154
|
+
rhsValue?: any; // Value to compare
|
|
155
|
+
rhsType?: FilterRHSType; // "Constant" | "Field"
|
|
156
|
+
children?: FilterConditionWithId[]; // Nested conditions (for logical operators)
|
|
157
|
+
isValid: boolean; // Validation state
|
|
158
|
+
validationErrors?: string[]; // Specific errors
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### TypedFilterConditionInput<T>
|
|
163
|
+
|
|
164
|
+
Type-safe input for addCondition:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
interface TypedFilterConditionInput<T> {
|
|
168
|
+
operator: FilterOperator | LogicalOperator;
|
|
169
|
+
lhsField?: keyof T & string; // Constrained to keys of T
|
|
170
|
+
rhsValue?: T[keyof T] | T[keyof T][] | any;
|
|
171
|
+
rhsType?: FilterRHSType;
|
|
172
|
+
children?: TypedFilterConditionInput<T>[];
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Filter Operators
|
|
177
|
+
|
|
178
|
+
### Comparison Operators
|
|
179
|
+
| Operator | Description | Example |
|
|
180
|
+
|----------|-------------|---------|
|
|
181
|
+
| `EQ` | Equal | `Price = 100` |
|
|
182
|
+
| `NE` | Not Equal | `Status != "Active"` |
|
|
183
|
+
| `GT` | Greater Than | `Stock > 0` |
|
|
184
|
+
| `GTE` | Greater Than or Equal | `Price >= 50` |
|
|
185
|
+
| `LT` | Less Than | `Rating < 3` |
|
|
186
|
+
| `LTE` | Less Than or Equal | `Discount <= 20` |
|
|
187
|
+
|
|
188
|
+
### Range Operators
|
|
189
|
+
| Operator | Description | RHS Format |
|
|
190
|
+
|----------|-------------|------------|
|
|
191
|
+
| `Between` | Between two values | `[min, max]` |
|
|
192
|
+
| `NotBetween` | Not between two values | `[min, max]` |
|
|
193
|
+
|
|
194
|
+
### Set Operators
|
|
195
|
+
| Operator | Description | RHS Format |
|
|
196
|
+
|----------|-------------|------------|
|
|
197
|
+
| `IN` | In array | `[value1, value2, ...]` |
|
|
198
|
+
| `NIN` | Not in array | `[value1, value2, ...]` |
|
|
199
|
+
|
|
200
|
+
### String Operators
|
|
201
|
+
| Operator | Description |
|
|
202
|
+
|----------|-------------|
|
|
203
|
+
| `Contains` | Contains substring |
|
|
204
|
+
| `NotContains` | Does not contain substring |
|
|
205
|
+
| `StartsWith` | Starts with string |
|
|
206
|
+
| `EndsWith` | Ends with string |
|
|
207
|
+
|
|
208
|
+
### Null Operators
|
|
209
|
+
| Operator | Description | RHS Required |
|
|
210
|
+
|----------|-------------|--------------|
|
|
211
|
+
| `Empty` | Is empty/null | No |
|
|
212
|
+
| `NotEmpty` | Is not empty/null | No |
|
|
213
|
+
|
|
214
|
+
### Logical Operators (for nesting)
|
|
215
|
+
| Operator | Description |
|
|
216
|
+
|----------|-------------|
|
|
217
|
+
| `And` | All children must match |
|
|
218
|
+
| `Or` | Any child must match |
|
|
219
|
+
| `Not` | Negate child (single child only) |
|
|
220
|
+
|
|
221
|
+
## E-Commerce App Usage Examples
|
|
222
|
+
|
|
223
|
+
### Category Filter (BuyerProductListPage.tsx)
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const handleCategoryChange = (category: string) => {
|
|
227
|
+
table.filter.clearConditions();
|
|
228
|
+
if (category !== "all") {
|
|
229
|
+
table.filter.addCondition({
|
|
230
|
+
lhsField: "Category",
|
|
231
|
+
operator: "EQ",
|
|
232
|
+
rhsValue: category,
|
|
233
|
+
rhsType: "Constant",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Price Range Filter
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
const PRICE_RANGES = [
|
|
243
|
+
{ label: "Under $25", min: 0, max: 25 },
|
|
244
|
+
{ label: "$25 to $50", min: 25, max: 50 },
|
|
245
|
+
{ label: "$50 to $100", min: 50, max: 100 },
|
|
246
|
+
{ label: "$100 to $200", min: 100, max: 200 },
|
|
247
|
+
{ label: "$200 & Above", min: 200, max: null },
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
const handlePriceChange = (rangeLabel: string) => {
|
|
251
|
+
const range = PRICE_RANGES.find((r) => r.label === rangeLabel);
|
|
252
|
+
if (range) {
|
|
253
|
+
if (range.max === null) {
|
|
254
|
+
// "$200 & Above" - use GTE
|
|
255
|
+
table.filter.addCondition({
|
|
256
|
+
lhsField: "Price",
|
|
257
|
+
operator: "GTE",
|
|
258
|
+
rhsValue: range.min,
|
|
259
|
+
rhsType: "Constant",
|
|
260
|
+
});
|
|
261
|
+
} else if (range.min === 0) {
|
|
262
|
+
// "Under $25" - use LT
|
|
263
|
+
table.filter.addCondition({
|
|
264
|
+
lhsField: "Price",
|
|
265
|
+
operator: "LT",
|
|
266
|
+
rhsValue: range.max,
|
|
267
|
+
rhsType: "Constant",
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
// Range like "$25 to $50" - use Between
|
|
271
|
+
table.filter.addCondition({
|
|
272
|
+
lhsField: "Price",
|
|
273
|
+
operator: "Between",
|
|
274
|
+
rhsValue: [range.min, range.max],
|
|
275
|
+
rhsType: "Constant",
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Multiple Filters Combined
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Apply both category and price filters
|
|
286
|
+
const applyFilters = (category: string, priceRange: string | null) => {
|
|
287
|
+
table.filter.clearConditions();
|
|
288
|
+
|
|
289
|
+
// Apply category filter
|
|
290
|
+
if (category !== "all") {
|
|
291
|
+
table.filter.addCondition({
|
|
292
|
+
lhsField: "Category",
|
|
293
|
+
operator: "EQ",
|
|
294
|
+
rhsValue: category,
|
|
295
|
+
rhsType: "Constant",
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Apply price filter
|
|
300
|
+
if (priceRange) {
|
|
301
|
+
const range = PRICE_RANGES.find((r) => r.label === priceRange);
|
|
302
|
+
if (range) {
|
|
303
|
+
table.filter.addCondition({
|
|
304
|
+
lhsField: "Price",
|
|
305
|
+
operator: "Between",
|
|
306
|
+
rhsValue: [range.min, range.max],
|
|
307
|
+
rhsType: "Constant",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Clear All Filters
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
<Button
|
|
318
|
+
onClick={() => {
|
|
319
|
+
table.search.clear();
|
|
320
|
+
table.filter.clearConditions();
|
|
321
|
+
setSelectedCategory("all");
|
|
322
|
+
setSelectedPriceRange(null);
|
|
323
|
+
}}
|
|
324
|
+
>
|
|
325
|
+
Clear All Filters
|
|
326
|
+
</Button>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Nested Logical Groups
|
|
330
|
+
|
|
331
|
+
Support for complex filter expressions:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
// (Category = "Electronics" AND Price > 100) OR Stock = 0
|
|
335
|
+
filter.addCondition({
|
|
336
|
+
operator: "Or",
|
|
337
|
+
children: [
|
|
338
|
+
{
|
|
339
|
+
operator: "And",
|
|
340
|
+
children: [
|
|
341
|
+
{ operator: "EQ", lhsField: "Category", rhsValue: "Electronics", rhsType: "Constant" },
|
|
342
|
+
{ operator: "GT", lhsField: "Price", rhsValue: 100, rhsType: "Constant" },
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
{ operator: "EQ", lhsField: "Stock", rhsValue: 0, rhsType: "Constant" },
|
|
346
|
+
],
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## API Payload Format
|
|
351
|
+
|
|
352
|
+
The hook generates payloads compatible with the backend API:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Single condition
|
|
356
|
+
{
|
|
357
|
+
Operator: "And",
|
|
358
|
+
Condition: [
|
|
359
|
+
{
|
|
360
|
+
Operator: "EQ",
|
|
361
|
+
LHSField: "Category",
|
|
362
|
+
RHSValue: "Electronics",
|
|
363
|
+
RHSType: "Constant"
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Multiple conditions
|
|
369
|
+
{
|
|
370
|
+
Operator: "And",
|
|
371
|
+
Condition: [
|
|
372
|
+
{ Operator: "EQ", LHSField: "Category", RHSValue: "Electronics", RHSType: "Constant" },
|
|
373
|
+
{ Operator: "GTE", LHSField: "Price", RHSValue: 50, RHSType: "Constant" }
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Nested logical groups
|
|
378
|
+
{
|
|
379
|
+
Operator: "Or",
|
|
380
|
+
Condition: [
|
|
381
|
+
{
|
|
382
|
+
Operator: "And",
|
|
383
|
+
Condition: [...]
|
|
384
|
+
},
|
|
385
|
+
{ Operator: "EQ", LHSField: "Stock", RHSValue: 0, RHSType: "Constant" }
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Validation
|
|
391
|
+
|
|
392
|
+
### Automatic Validation
|
|
393
|
+
|
|
394
|
+
Conditions are validated on add/update:
|
|
395
|
+
- Operator is required
|
|
396
|
+
- lhsField is required for condition operators
|
|
397
|
+
- rhsValue format matches operator requirements
|
|
398
|
+
- Field-specific validation if fieldDefinitions provided
|
|
399
|
+
|
|
400
|
+
### Validation Errors
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
interface ValidationError {
|
|
404
|
+
conditionId: string;
|
|
405
|
+
field: string;
|
|
406
|
+
message: string;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Access validation errors
|
|
410
|
+
filter.validationErrors.forEach((error) => {
|
|
411
|
+
console.log(`${error.field}: ${error.message}`);
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Custom Field Validation
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
const filter = useFilter<Product>({
|
|
419
|
+
fieldDefinitions: {
|
|
420
|
+
Price: {
|
|
421
|
+
type: "number",
|
|
422
|
+
allowedOperators: ["EQ", "GT", "LT", "GTE", "LTE", "Between"],
|
|
423
|
+
validateValue: (value, operator) => {
|
|
424
|
+
if (value < 0) {
|
|
425
|
+
return { isValid: false, errors: ["Price cannot be negative"] };
|
|
426
|
+
}
|
|
427
|
+
return { isValid: true, errors: [] };
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## State Management
|
|
435
|
+
|
|
436
|
+
### Export/Import State
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
// Export current state
|
|
440
|
+
const savedState = filter.exportState();
|
|
441
|
+
localStorage.setItem("filters", JSON.stringify(savedState));
|
|
442
|
+
|
|
443
|
+
// Import saved state
|
|
444
|
+
const savedState = JSON.parse(localStorage.getItem("filters"));
|
|
445
|
+
filter.importState(savedState);
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Reset to Initial
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
filter.resetToInitial();
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Key Behaviors
|
|
455
|
+
|
|
456
|
+
1. **Auto-validation**: Conditions validated on add/update
|
|
457
|
+
2. **Type-safe lhsField**: Constrained to `keyof T` at compile time
|
|
458
|
+
3. **Only valid in payload**: Only valid conditions included in filterPayload
|
|
459
|
+
4. **UUID generation**: Uses `crypto.randomUUID()` for condition IDs
|
|
460
|
+
5. **Deep copy on export**: Exported state is a deep copy
|
|
461
|
+
6. **Nested group support**: Full support for And/Or/Not logical nesting
|
|
462
|
+
|
|
463
|
+
## Integration with useTable
|
|
464
|
+
|
|
465
|
+
The useFilter hook is automatically integrated into useTable:
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
const table = useTable<Product>({
|
|
469
|
+
source: "BDO_Products",
|
|
470
|
+
enableFiltering: true,
|
|
471
|
+
initialState: {
|
|
472
|
+
filters: [...],
|
|
473
|
+
filterOperator: "And",
|
|
474
|
+
},
|
|
475
|
+
onFilterError: (errors) => console.log(errors),
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// Access filter through table.filter
|
|
479
|
+
table.filter.addCondition({...});
|
|
480
|
+
table.filter.clearConditions();
|
|
481
|
+
table.filter.conditions;
|
|
482
|
+
table.filter.isValid;
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Filter changes automatically:
|
|
486
|
+
- Reset pagination to page 1
|
|
487
|
+
- Trigger data refetch
|
|
488
|
+
- Update count query
|
|
489
|
+
|
|
490
|
+
## Architecture Notes
|
|
491
|
+
|
|
492
|
+
- Uses `useState` for internal state management
|
|
493
|
+
- Generates UUIDs for condition tracking
|
|
494
|
+
- Recursive validation for nested groups
|
|
495
|
+
- Memoized filterPayload computation
|
|
496
|
+
- Type-safe with full TypeScript generics
|
|
497
|
+
- Integrates seamlessly with useTable
|