# ISA Filter Library

A powerful and flexible filtering library for Angular applications that provides a complete solution for implementing filters, search functionality, and sorting capabilities.

## Overview

The ISA Filter Library is designed to help developers quickly implement advanced filtering capabilities in their Angular applications. It provides a set of reusable components, schemas, and services to handle various types of filters, user inputs, and sorting options.

## Features

- **Multiple Filter Types**: Support for text search, checkboxes, date ranges, and more
- **Flexible Architecture**: Easily extendable to support custom filter types
- **Modern Angular Patterns**: Built with Angular signals for reactive state management
- **Schema-based Validation**: Type-safe filter models with zod schema validation
- **Responsive Design**: Mobile-friendly filter UI components
- **Declarative API**: Simple and intuitive API for configuring filters
- **Sorting Capabilities**: Built-in support for sorting data by various criteria
- **TypeScript Support**: Fully typed for excellent developer experience

## Installation

The library is part of the ISA Frontend monorepo and can be imported using:

```typescript
import { ... } from '@isa/shared/filter';
```

## Core Concepts

### Filter Service

The `FilterService` is the central component of the library, responsible for managing filter state and providing methods to update and query filter values.

```typescript
// Example of using FilterService
export class MyComponent {
  constructor(private filterService: FilterService) {}

  applyFilters() {
    // Apply filters and get the query
    const query = this.filterService.getQuery();
    // Use the query to fetch filtered data
  }

  resetFilters() {
    this.filterService.reset();
  }
}
```

### Filter Types

The library supports several filter input types:

- **Text Filters** (`InputType.Text`): For search queries and text-based filtering
- **Checkbox Filters** (`InputType.Checkbox`): For multi-select options with optional selection limits
- **Date Range Filters** (`InputType.DateRange`): For time-based filtering

### Query Settings

Filter configurations are defined using the `QuerySettings` interface, which includes filter groups, input fields, and sort options.

```typescript
// Example QuerySettings configuration
const settings: QuerySettings = {
  filter: [
    {
      group: 'products',
      label: 'Product Filters',
      input: [
        {
          key: 'category',
          label: 'Category',
          type: InputType.Checkbox,
          options: {
            max: 3, // Optional: Limit selection to 3 items
            values: [
              { label: 'Electronics', value: 'electronics' },
              { label: 'Clothing', value: 'clothing' },
              { label: 'Books', value: 'books' },
              { label: 'Sports', value: 'sports' },
            ],
          },
        },
      ],
    },
  ],
  input: [],
  orderBy: [
    { by: 'price', label: 'Price (Low to High)', desc: false },
    { by: 'price', label: 'Price (High to Low)', desc: true },
  ],
};
```

## Components

### Filter Menu

The `FilterMenuComponent` provides a UI for displaying and interacting with filters:

```html
<filter-filter-menu (applied)="onApplyFilters()" (reseted)="onResetFilters()">
</filter-filter-menu>
```

### Order By Toolbar

The `OrderByToolbarComponent` allows users to sort data based on different criteria:

```html
<filter-order-by-toolbar [commitOnToggle]="true" (toggled)="onSortChanged()">
</filter-order-by-toolbar>
```

### Input Components

The library includes specialized components for different input types:

- `CheckboxInputComponent`: For multi-select options with optional selection limits
- `DatepickerRangeInputComponent`: For date range selection
- `SearchBarInputComponent`: For text-based search

### Input Renderer

The `InputRendererComponent` dynamically renders the appropriate input component based on the filter type:

```html
<filter-input-renderer [filterInput]="myFilterInput"></filter-input-renderer>
```

## Usage Examples

### Basic Filter Implementation

```typescript
// Import filter library
import { QuerySettings, InputType, provideFilter } from '@isa/shared/filter';

// Define filter settings
const settings: QuerySettings = {
  filter: [
    {
      group: 'filter',
      label: 'Filters',
      input: [
        {
          key: 'status',
          label: 'Status',
          type: InputType.Checkbox,
          options: {
            max: 2, // Allow up to 2 status selections
            values: [
              { label: 'Active', value: 'active' },
              { label: 'Inactive', value: 'inactive' },
              { label: 'Pending', value: 'pending' },
            ],
          },
        },
      ],
    },
  ],
  input: [],
  orderBy: [
    { by: 'name', label: 'Name (A-Z)', desc: false },
    { by: 'name', label: 'Name (Z-A)', desc: true },
  ],
};

// Provide filter in component/module
@Component({
  // ...
  providers: [provideFilter(settings)],
})
export class MyFilterComponent {
  // ...
}
```

### Implementing Filter Logic

```typescript
@Component({
  // ...
})
export class ProductListComponent {
  constructor(private filterService: FilterService) {}

  products = computed(() => {
    const query = this.filterService.getQuery();
    return this.applyFilters(this.allProducts, query);
  });

  private applyFilters(products: Product[], query: Query): Product[] {
    // Implement filtering logic based on query
    return filteredProducts;
  }

  onApplyFilters() {
    // Trigger data refresh or update
    this.filterService.commit();
  }
}
```

### Maximum Options for Checkbox Filters

Checkbox filters support an optional `max` property to limit the number of selections users can make:

```typescript
// Configuration with maximum options
{
  key: 'tags',
  label: 'Tags',
  type: InputType.Checkbox,
  options: {
    max: 5, // Users can select up to 5 tags
    values: [
      { label: 'JavaScript', value: 'js' },
      { label: 'TypeScript', value: 'ts' },
      { label: 'Angular', value: 'angular' },
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Node.js', value: 'node' },
      { label: 'Python', value: 'python' },
    ],
  },
}
```

**Behavior with Maximum Options:**

- **FIFO Strategy**: When the limit is exceeded, the oldest selections are automatically removed
- **UI Enhancement**: The "Select All" control is hidden when `max` is configured to prevent user confusion
- **Automatic Enforcement**: The filter service handles limit enforcement transparently

**Example with FIFO Behavior:**
```typescript
// Starting state: [] (empty)
// User selects: ['js'] 
// User selects: ['js', 'ts']
// User selects: ['js', 'ts', 'angular'] 
// User selects: ['js', 'ts', 'angular', 'react']
// User selects: ['js', 'ts', 'angular', 'react', 'vue']
// User selects 'node' -> ['ts', 'angular', 'react', 'vue', 'node'] (oldest 'js' removed)
```
  }
}
```

## Schema Validation

The library uses Zod schemas to validate filter configurations and user inputs:

```typescript
// Example of a filter schema
export const CheckboxFilterInputSchema = CheckboxFilterInputBaseSchema.extend({
  options: z
    .object({
      values: z.array(CheckboxFilterInputOptionSchema).optional(),
      max: z.number().optional(),
    })
    .optional(),
  selected: z.array(z.string()).default([]),
  type: z.literal(InputType.Checkbox),
});
```

## Architecture

The Filter library is organized into several key modules:

### Core Module

- **Schemas**: Type definitions and validation using Zod
- **Mappings**: Functions to transform between API and UI models
- **Service**: The `FilterService` for state management
- **Tokens**: Injection tokens for DI configuration

### Inputs Module

- **CheckboxInput**: Multi-select options component with configurable selection limits
- **DatepickerRangeInput**: Date range selection component
- **SearchBarInput**: Text-based search component
- **InputRenderer**: Dynamic component renderer

### Menus Module

- **FilterMenu**: UI for displaying and interacting with filters
- **InputMenu**: Specialized component for input configuration

### Actions Module

Components for filter operations (apply, reset, etc.)

### Order By Module

Components for sorting data based on different criteria

## Best Practices

1. **Group Related Filters**: Use filter groups to organize related filters together
2. **Provide Clear Labels**: Use descriptive labels for filters and options
3. **Use Appropriate Filter Types**: Choose the right filter type for the data being filtered
4. **Handle Filter State**: Properly manage filter state, especially for URL synchronization
5. **Combine with NgRx**: For complex applications, consider using the library with NgRx for state management

## Running unit tests

Run `nx test shared-filter` to execute the unit tests.
