feat([2fd88f42]): redesign filter panel with modern checkbox UI

This commit is contained in:
2026-02-04 12:38:10 +00:00
parent 96505b68fc
commit 34f156e7e7

View File

@@ -14,61 +14,80 @@ interface FilterPanelProps {
const FilterPanel: React.FC<FilterPanelProps> = ({ filters, onFilterChange, isLoading }) => {
const [selectedFilters, setSelectedFilters] = useState<FilterOptions>({});
// Reset selected filters when a new file is uploaded (filters prop changes)
useEffect(() => {
setSelectedFilters({});
}, [filters]);
const handleSelectionChange = (category: string, values: string[]) => {
setSelectedFilters(prev => ({
...prev,
[category]: values,
}));
const handleCheckboxChange = (category: string, value: string) => {
setSelectedFilters(prev => {
const currentSelection = prev[category] || [];
const newSelection = currentSelection.includes(value)
? currentSelection.filter(item => item !== value)
// Ensure "N/A" is not sorted to the top if that's not desired
: [...currentSelection, value].sort((a, b) => a === 'N/A' ? 1 : b === 'N/A' ? -1 : a.localeCompare(b));
return { ...prev, [category]: newSelection };
});
};
const handleApplyClick = () => {
onFilterChange(selectedFilters);
}
onFilterChange(selectedFilters);
};
const handleResetClick = () => {
setSelectedFilters({});
onFilterChange({});
}
};
if (Object.keys(filters).length === 0) {
return <div>Upload a file to see filter options.</div>;
}
return (
<div className="filter-panel">
<h3>Filters</h3>
{Object.entries(filters).map(([category, options]) => (
<div key={category} className="filter-group">
<label>{category}</label>
<select
multiple
value={selectedFilters[category] || []}
onChange={(e) =>
handleSelectionChange(category, Array.from(e.target.selectedOptions, option => option.value))
}
>
{options.map(option => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<>
<style>{`
.filter-panel { padding-top: 20px; }
.filter-group { margin-bottom: 15px; }
.filter-group summary { font-weight: bold; cursor: pointer; padding: 5px; background-color: #444; border-radius: 4px; }
.filter-options { max-height: 200px; overflow-y: auto; padding: 10px; background-color: #2a2a2a; border-radius: 4px; margin-top: 5px;}
.filter-option { display: flex; align-items: center; margin-bottom: 5px; }
.filter-option input { margin-right: 10px; }
.filter-buttons { margin-top: 20px; display: flex; justify-content: space-between; }
.filter-buttons button { width: 48%; padding: 10px; border: none; border-radius: 4px; cursor: pointer; }
.apply-button { background-color: #4CAF50; color: white; }
.reset-button { background-color: #f44336; color: white; }
.filter-buttons button:disabled { background-color: #555; cursor: not-allowed; }
`}</style>
<div className="filter-panel">
<h3>Filters</h3>
{Object.entries(filters).map(([category, options]) => (
<details key={category} className="filter-group" open>
<summary>{category}</summary>
<div className="filter-options">
{options.map(option => (
<div key={option} className="filter-option">
<input
type="checkbox"
id={`${category}-${option}`}
value={option}
checked={(selectedFilters[category] || []).includes(option)}
onChange={() => handleCheckboxChange(category, option)}
/>
<label htmlFor={`${category}-${option}`}>{option}</label>
</div>
))}
</div>
</details>
))}
<div className="filter-buttons">
<button onClick={handleApplyClick} disabled={isLoading} className="apply-button">
{isLoading ? 'Loading...' : 'Apply Filters'}
</button>
<button onClick={handleResetClick} disabled={isLoading} className="reset-button">
Reset
</button>
</div>
))}
<div className="filter-buttons">
<button onClick={handleApplyClick} disabled={isLoading}>
{isLoading ? 'Loading...' : 'Apply Filters'}
</button>
<button onClick={handleResetClick} disabled={isLoading}>
Reset Filters
</button>
</div>
</div>
</>
);
};