From 9681827395564751e544121c832f81c492e4fd6f Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Tue, 28 Jul 2026 21:32:29 +0200 Subject: [PATCH] fix: saved filters now persistent via API (was local state) --- frontend/src/pages/ContactsList.tsx | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/frontend/src/pages/ContactsList.tsx b/frontend/src/pages/ContactsList.tsx index 8368b86..17f874b 100644 --- a/frontend/src/pages/ContactsList.tsx +++ b/frontend/src/pages/ContactsList.tsx @@ -25,6 +25,7 @@ import { SortPanel, applySorting, emptySortState, type SortState } from '@/compo import { GroupPanel, applyGrouping, emptyGroupState, type GroupState, type GroupedContacts } from '@/components/contacts/GroupPanel'; import { SaveViewDialog, type SaveViewSelection } from '@/components/contacts/SaveViewDialog'; import { useSavedViews, useCreateSavedView, useDeleteSavedView } from '@/api/savedViews'; +import { useSavedFilters as useSavedFiltersApi, useCreateSavedFilter, useDeleteSavedFilter } from '@/api/savedFilters'; import { useUnifiedContacts, useUnifiedContact, @@ -54,7 +55,6 @@ export function ContactsListPage() { const [foldersOpen, setFoldersOpen] = useState(true); const [multiSelectFolders, setMultiSelectFolders] = useState([]); const [activeViewId, setActiveViewId] = useState(null); - const [savedFilters, setSavedFilters] = useState([]); const [saveViewDialogOpen, setSaveViewDialogOpen] = useState(false); const openWindow = useWindowStore((s) => s.openWindow); @@ -64,6 +64,17 @@ export function ContactsListPage() { const deleteViewMut = useDeleteSavedView(); const savedViews = apiSavedViews ?? []; + // Saved filters from API (durable, per-user) + const { data: apiSavedFilters } = useSavedFiltersApi('contacts'); + const createFilterMut = useCreateSavedFilter(); + const deleteFilterMut = useDeleteSavedFilter(); + // Map API saved filters to FilterPanel SavedFilter format + const savedFilters: SavedFilter[] = (apiSavedFilters ?? []).map((f) => ({ + id: f.id, + name: f.name, + filterState: f.filter_criteria as FilterState, + })); + // Debounce search useEffect(() => { const timer = setTimeout(() => setDebouncedSearch(search), 300); @@ -253,11 +264,10 @@ export function ContactsListPage() { if (activeViewId === id) setActiveViewId(null); }, [activeViewId, deleteViewMut]); - // Save current filter configuration + // Save current filter configuration — via API 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 })) } }]); - }, []); + createFilterMut.mutate({ name, entity_type: 'contacts', filter_criteria: filterState as any }); + }, [createFilterMut]); // Load a saved filter const handleLoadFilter = useCallback((filterState: FilterState) => { @@ -265,10 +275,10 @@ export function ContactsListPage() { setPage(1); }, []); - // Delete a saved filter + // Delete a saved filter — via API const handleDeleteFilter = useCallback((id: string) => { - setSavedFilters((prev) => prev.filter((f) => f.id !== id)); - }, []); + deleteFilterMut.mutate(id); + }, [deleteFilterMut]); // Sort options const sortOptions = useMemo(() => [ @@ -415,7 +425,7 @@ export function ContactsListPage() { ]; registerItems('contacts', items); return () => unregisterPlugin('contacts'); - }, [handleSearch, handleCreate, handleSelectFilter, handleSaveView, applySavedView, deleteSavedView, handleSaveViewConfirm, handleSaveFilter, handleLoadFilter, handleDeleteFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState, groupState, savedViews, activeViewId, multiSelectFolders, savedFilters, saveViewDialogOpen]); + }, [handleSearch, handleCreate, handleSelectFilter, handleSaveView, applySavedView, deleteSavedView, handleSaveViewConfirm, handleSaveFilter, handleLoadFilter, handleDeleteFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState, groupState, savedViews, activeViewId, multiSelectFolders, saveViewDialogOpen]); return (