import React, { useState } from 'react';
import { FilterConfig, FilterOption, FilterType } from '../../types';
export interface FilterComponentProps {
config: FilterConfig;
value: any;
onChange: (value: any) => void;
size?: 'sm' | 'md' | 'lg';
className?: string;
}
/**
* Select Filter Component
*/
export function SelectFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
return (
{config.label}
onChange(e.target.value || undefined)}
>
{config.placeholder || 'All'}
{config.options?.map((option) => (
{option.label}
))}
{value && (
onChange(undefined)}
aria-label={`Clear ${config.label} filter`}
title="Clear filter"
>
×
)}
);
}
/**
* Text Filter Component
*/
export function TextFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
return (
);
}
/**
* Number Filter Component
*/
export function NumberFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
return (
);
}
/**
* Date Filter Component
*/
export function DateFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
return (
);
}
/**
* Boolean Filter Component
*/
export function BooleanFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
return (
{config.label}
{
const val = e.target.value;
if (val === '') {
onChange(undefined);
} else if (val === 'true') {
onChange(true);
} else {
onChange(false);
}
}}
>
All
Yes
No
{value !== undefined && (
onChange(undefined)}
aria-label={`Clear ${config.label} filter`}
title="Clear filter"
>
×
)}
);
}
/**
* Date Range Filter Component
*/
export function DateRangeFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
// Initialize with empty range if not set
const range = value || { start: '', end: '' };
// Handle start date change
const handleStartChange = (e: React.ChangeEvent) => {
onChange({ ...range, start: e.target.value });
};
// Handle end date change
const handleEndChange = (e: React.ChangeEvent) => {
onChange({ ...range, end: e.target.value });
};
return (
);
}
/**
* Number Range Filter Component
*/
export function NumberRangeFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
// Initialize with empty range if not set
const range = value || { min: '', max: '' };
// Handle min value change
const handleMinChange = (e: React.ChangeEvent) => {
onChange({ ...range, min: e.target.value === '' ? '' : Number(e.target.value) });
};
// Handle max value change
const handleMaxChange = (e: React.ChangeEvent) => {
onChange({ ...range, max: e.target.value === '' ? '' : Number(e.target.value) });
};
return (
);
}
/**
* Multi-select Filter Component
*/
export function MultiSelectFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) {
const [isOpen, setIsOpen] = useState(false);
// Convert value to array if not already
const selectedValues = Array.isArray(value) ? value : (value ? [value] : []);
// Toggle selection of an option
const toggleOption = (optionValue: any) => {
if (selectedValues.includes(optionValue)) {
onChange(selectedValues.filter(v => v !== optionValue));
} else {
onChange([...selectedValues, optionValue]);
}
};
return (
{config.label}
setIsOpen(!isOpen)}
>
{selectedValues.length === 0 ? (
{config.placeholder || 'Select options'}
) : (
{config.options
?.filter(opt => selectedValues.includes(opt.value))
.map(opt => opt.label)
.join(', ')}
)}
{selectedValues.length > 0 && (
{
e.stopPropagation(); // Prevent dropdown from toggling
onChange([]);
}}
aria-label={`Clear ${config.label} filter`}
title="Clear selections"
>
×
)}
▼
{isOpen && (
{config.options?.map((option) => (
toggleOption(option.value)}
>
{}} // Handled by parent div click
readOnly
/>
{option.label}
))}
)}
);
}
/**
* Factory function to create a filter component based on filter type
*/
export function createFilterComponent(config: FilterConfig, value: any, onChange: (value: any) => void) {
switch (config.type) {
case 'select':
return ;
case 'text':
return ;
case 'number':
return ;
case 'date':
return ;
case 'boolean':
return ;
case 'dateRange':
return ;
case 'multiselect':
return ;
default:
return ;
}
}