feat: SmartSuite-style SortPanel with multi-field priority sorting, all contact fields
This commit is contained in:
@@ -21,6 +21,7 @@ import { TagSelector } from '@/components/tags/TagSelector';
|
||||
import type { Tag } from '@/api/tags';
|
||||
import { ArrowDownAZ, ArrowUpZA, Bookmark, ChevronLeft, ExternalLink, LayoutGrid, List, Plus, Printer, Table2 } from 'lucide-react';
|
||||
import { FilterPanel, applyFilters, emptyFilterState, type FilterState } from '@/components/contacts/FilterPanel';
|
||||
import { SortPanel, applySorting, emptySortState, type SortState } from '@/components/contacts/SortPanel';
|
||||
import {
|
||||
useUnifiedContacts,
|
||||
useUnifiedContact,
|
||||
@@ -44,6 +45,7 @@ export function ContactsListPage() {
|
||||
const [savedFiltersOpen, setSavedFiltersOpen] = useState(false);
|
||||
const [selectedTags, setSelectedTags] = useState<Tag[]>([]);
|
||||
const [filterState, setFilterState] = useState<FilterState>(emptyFilterState);
|
||||
const [sortState, setSortState] = useState<SortState>(emptySortState);
|
||||
const openWindow = useWindowStore((s) => s.openWindow);
|
||||
|
||||
// Debounce search
|
||||
@@ -113,8 +115,10 @@ export function ContactsListPage() {
|
||||
}
|
||||
// Apply FilterPanel conditions
|
||||
result = applyFilters(result, filterState);
|
||||
// Apply SortPanel sorting
|
||||
result = applySorting(result, sortState);
|
||||
return result;
|
||||
}, [contacts, tagFilter, filterState]);
|
||||
}, [contacts, tagFilter, filterState, sortState]);
|
||||
|
||||
// Handle folder selection
|
||||
const handleSelectFilter = useCallback((filter: ContactFilter) => {
|
||||
@@ -232,26 +236,20 @@ export function ContactsListPage() {
|
||||
),
|
||||
onClick: () => {},
|
||||
},
|
||||
// Sort dropdown
|
||||
// SortPanel — SmartSuite-style multi-field sort
|
||||
{
|
||||
id: 'sort-by',
|
||||
id: 'sort-panel',
|
||||
plugin: 'contacts',
|
||||
label: t('common.sort', 'Sortieren'),
|
||||
type: 'dropdown' as const,
|
||||
label: 'Sortieren',
|
||||
type: 'custom' as const,
|
||||
group: 'sort',
|
||||
icon: <ArrowDownAZ className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
menuWidth: '200px',
|
||||
menuOptions: [
|
||||
...sortOptions.map((opt) => ({
|
||||
value: `sort-${opt.value}`, label: opt.label, section: t('common.sortBy', 'Sortieren nach'),
|
||||
active: sortBy === opt.value, onClick: () => { setSortBy(opt.value); setPage(1); },
|
||||
})),
|
||||
{ value: 'sep-order', label: '', separator: true, onClick: () => {} },
|
||||
{ value: 'sort-asc', label: t('common.sortAsc', 'Aufsteigend'), section: t('common.sortOrder', 'Reihenfolge'),
|
||||
icon: <ArrowDownAZ className="w-3.5 h-3.5" strokeWidth={2} />, active: sortOrder === 'asc', onClick: () => handleSortChange(sortBy, 'asc') },
|
||||
{ value: 'sort-desc', label: t('common.sortDesc', 'Absteigend'),
|
||||
icon: <ArrowUpZA className="w-3.5 h-3.5" strokeWidth={2} />, active: sortOrder === 'desc', onClick: () => handleSortChange(sortBy, 'desc') },
|
||||
],
|
||||
customComponent: (
|
||||
<SortPanel
|
||||
sortState={sortState}
|
||||
onSortChange={setSortState}
|
||||
contactType={contactType}
|
||||
/>
|
||||
),
|
||||
onClick: () => {},
|
||||
},
|
||||
// View mode dropdown (list / table / cards)
|
||||
@@ -313,7 +311,7 @@ export function ContactsListPage() {
|
||||
];
|
||||
registerItems('contacts', items);
|
||||
return () => unregisterPlugin('contacts');
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, handleSortChange, t, registerItems, unregisterPlugin, sortBy, sortOrder, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType]);
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full" data-testid="contacts-list-page">
|
||||
|
||||
Reference in New Issue
Block a user