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}
{value && ( )}
); } /** * Text Filter Component */ export function TextFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) { return (
{config.label}
onChange(e.target.value)} placeholder={config.placeholder || `Filter by ${config.label}`} /> {value && ( )}
); } /** * Number Filter Component */ export function NumberFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) { return (
{config.label}
onChange(e.target.value === '' ? undefined : Number(e.target.value))} placeholder={config.placeholder || `Filter by ${config.label}`} /> {(value !== undefined && value !== null) && ( )}
); } /** * Date Filter Component */ export function DateFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) { return (
{config.label}
onChange(e.target.value)} /> {value && ( )}
); } /** * Boolean Filter Component */ export function BooleanFilter({ config, value, onChange, size = 'md', className }: FilterComponentProps) { return (
{config.label}
{value !== undefined && ( )}
); } /** * 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 (
{config.label}
to {(range.start || range.end) && ( )}
); } /** * 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 (
{config.label}
to {(range.min !== '' || range.max !== '') && ( )}
); } /** * 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 && ( )}
{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 ; } }