feat: save/load/delete filters directly in FilterPanel dropdown
This commit is contained in:
@@ -20,7 +20,7 @@ import { SavedFilterBar } from '@/components/common/SavedFilterBar';
|
||||
import { TagSelector } from '@/components/tags/TagSelector';
|
||||
import type { Tag } from '@/api/tags';
|
||||
import { ArrowDownAZ, ArrowUpZA, Bookmark, ChevronLeft, ExternalLink, LayoutGrid, List, Plus, Printer, Table2, X } from 'lucide-react';
|
||||
import { FilterPanel, applyFilters, emptyFilterState, type FilterState } from '@/components/contacts/FilterPanel';
|
||||
import { FilterPanel, applyFilters, emptyFilterState, type FilterState, type SavedFilter } from '@/components/contacts/FilterPanel';
|
||||
import { SortPanel, applySorting, emptySortState, type SortState } from '@/components/contacts/SortPanel';
|
||||
import { GroupPanel, applyGrouping, emptyGroupState, type GroupState, type GroupedContacts } from '@/components/contacts/GroupPanel';
|
||||
import {
|
||||
@@ -53,6 +53,7 @@ export function ContactsListPage() {
|
||||
const [multiSelectFolders, setMultiSelectFolders] = useState<string[]>([]);
|
||||
const [savedViews, setSavedViews] = useState<{ id: string; name: string; filterState: FilterState; sortState: SortState; groupState: GroupState; selectedFilter: ContactFilter; viewMode: ContactViewMode }[]>([]);
|
||||
const [activeViewId, setActiveViewId] = useState<string | null>(null);
|
||||
const [savedFilters, setSavedFilters] = useState<SavedFilter[]>([]);
|
||||
const openWindow = useWindowStore((s) => s.openWindow);
|
||||
|
||||
// Debounce search
|
||||
@@ -235,6 +236,23 @@ export function ContactsListPage() {
|
||||
if (activeViewId === id) setActiveViewId(null);
|
||||
}, [activeViewId]);
|
||||
|
||||
// Save current filter configuration
|
||||
const handleSaveFilter = useCallback((name: string, filterState: FilterState) => {
|
||||
const id = `filter-${Date.now()}`;
|
||||
setSavedFilters((prev) => [...prev, { id, name, filterState: { ...filterState, conditions: filterState.conditions.map((c) => ({ ...c })) } }]);
|
||||
}, []);
|
||||
|
||||
// Load a saved filter
|
||||
const handleLoadFilter = useCallback((filterState: FilterState) => {
|
||||
setFilterState({ ...filterState, conditions: filterState.conditions.map((c) => ({ ...c })) });
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
// Delete a saved filter
|
||||
const handleDeleteFilter = useCallback((id: string) => {
|
||||
setSavedFilters((prev) => prev.filter((f) => f.id !== id));
|
||||
}, []);
|
||||
|
||||
// Sort options
|
||||
const sortOptions = useMemo(() => [
|
||||
{ value: 'displayname', label: t('contacts.fullName') },
|
||||
@@ -305,6 +323,10 @@ export function ContactsListPage() {
|
||||
filters={filterState}
|
||||
onFiltersChange={setFilterState}
|
||||
contactType={contactType}
|
||||
savedFilters={savedFilters}
|
||||
onSaveFilter={handleSaveFilter}
|
||||
onLoadFilter={handleLoadFilter}
|
||||
onDeleteFilter={handleDeleteFilter}
|
||||
/>
|
||||
),
|
||||
onClick: () => {},
|
||||
@@ -376,7 +398,7 @@ export function ContactsListPage() {
|
||||
];
|
||||
registerItems('contacts', items);
|
||||
return () => unregisterPlugin('contacts');
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, handleSaveView, applySavedView, deleteSavedView, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState, groupState, savedViews, activeViewId, multiSelectFolders]);
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, handleSaveView, applySavedView, deleteSavedView, handleSaveFilter, handleLoadFilter, handleDeleteFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState, groupState, savedViews, activeViewId, multiSelectFolders, savedFilters]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full" data-testid="contacts-list-page">
|
||||
|
||||
Reference in New Issue
Block a user