import { forwardRef, useState, useMemo } from 'react' import { FilterType, ColumnDefinition, type ColumnFilter } from '../types' import { getColumnTypeConfig } from '../columnTypes' import { getUniqueColumnValues } from '../utils' import Block from '../../Primitives/Block/Block' import PrimitiveText from '../../Primitives/PrimitiveText/PrimitiveText' import { SearchInput } from '../../Inputs/SearchInput' import MultiSelectMenu from '../../MultiSelect/MultiSelectMenu' import SingleSelectMenu from '../../SingleSelect/SingleSelectMenu' import { FOUNDATION_THEME } from '../../../tokens' import { SelectMenuGroupType } from '../../Select/types' import { useResponsiveTokens } from '../../../hooks/useResponsiveTokens' import type { TableTokenType } from '../dataTable.tokens' export type ColumnFilterProps> = { column: ColumnDefinition data: T[] currentFilter?: ColumnFilter onFilter: ( field: keyof T, type: FilterType, value: string | string[], operator?: string ) => void } const ColumnFilter = forwardRef< HTMLDivElement, ColumnFilterProps> >(({ column, data, currentFilter, onFilter }, ref) => { const tableToken = useResponsiveTokens('TABLE') const filterToken = tableToken.dataTable.table.header.filter const [searchValue, setSearchValue] = useState( (currentFilter?.value as string) || '' ) const [selectedValues, setSelectedValues] = useState( Array.isArray(currentFilter?.value) ? currentFilter.value : currentFilter?.value ? [currentFilter.value as string] : [] ) const [isSelectOpen, setIsSelectOpen] = useState(false) const [isMultiSelectOpen, setIsMultiSelectOpen] = useState(false) const columnConfig = getColumnTypeConfig(column.type) const filterOptions = useMemo(() => { if (column.filterOptions) { return column.filterOptions.map((option) => ({ id: option.id, label: option.label, value: option.value, })) } const uniqueValues = getUniqueColumnValues(data, column.field) return uniqueValues.map((val) => ({ id: String(val), label: String(val), value: String(val), })) }, [data, column.field, column.filterOptions]) const menuItems: SelectMenuGroupType[] = [ { groupLabel: `${column.header} Options`, items: filterOptions.map((option) => ({ label: option.label, value: option.value, onClick: () => {}, })), showSeparator: false, }, ] const handleSearchChange = (event: React.ChangeEvent) => { const value = event.target.value setSearchValue(value) onFilter(column.field, FilterType.TEXT, value, 'contains') } const handleSingleSelect = (value: string) => { setSelectedValues([value]) onFilter(column.field, FilterType.SELECT, value, 'equals') setIsSelectOpen(false) } const handleMultiSelect = (value: string) => { let newSelected = [...selectedValues] if (newSelected.includes(value)) { newSelected = newSelected.filter((v) => v !== value) } else { newSelected.push(value) } setSelectedValues(newSelected) onFilter(column.field, FilterType.MULTISELECT, newSelected, 'equals') } const clearFilter = () => { setSearchValue('') setSelectedValues([]) onFilter( column.field, column.filterType || FilterType.TEXT, '', 'equals' ) } if (!columnConfig.supportsFiltering) { return null } return ( Filter {column.header} {(searchValue || selectedValues.length > 0) && ( Clear )} {columnConfig.filterComponent === 'search' && ( )} {columnConfig.filterComponent === 'select' && ( {selectedValues[0] ? filterOptions.find( (opt) => opt.value === selectedValues[0] )?.label || selectedValues[0] : 'Select option...'} ▼ } /> )} {columnConfig.filterComponent === 'multiselect' && ( 0 ? filterToken.selectedTextColor : filterToken.normalTextColor, }} > {selectedValues.length > 0 ? `${selectedValues.length} selected` : 'Select options...'} ▼ } /> )} {columnConfig.filterComponent === 'numberRange' && ( Number range filtering coming soon... )} ) }) ColumnFilter.displayName = 'ColumnFilter' export default ColumnFilter