feat: GroupPanel + toolbar reorder (New, View, Search, Filter, Sort, Group)
This commit is contained in:
@@ -22,6 +22,7 @@ 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 { GroupPanel, applyGrouping, emptyGroupState, type GroupState, type GroupedContacts } from '@/components/contacts/GroupPanel';
|
||||
import {
|
||||
useUnifiedContacts,
|
||||
useUnifiedContact,
|
||||
@@ -46,6 +47,7 @@ export function ContactsListPage() {
|
||||
const [selectedTags, setSelectedTags] = useState<Tag[]>([]);
|
||||
const [filterState, setFilterState] = useState<FilterState>(emptyFilterState);
|
||||
const [sortState, setSortState] = useState<SortState>(emptySortState);
|
||||
const [groupState, setGroupState] = useState<GroupState>(emptyGroupState);
|
||||
const openWindow = useWindowStore((s) => s.openWindow);
|
||||
|
||||
// Debounce search
|
||||
@@ -120,6 +122,9 @@ export function ContactsListPage() {
|
||||
return result;
|
||||
}, [contacts, tagFilter, filterState, sortState]);
|
||||
|
||||
// Apply GroupPanel grouping
|
||||
const groupedContacts = useMemo(() => applyGrouping(filteredContacts, groupState), [filteredContacts, groupState]);
|
||||
|
||||
// Handle folder selection
|
||||
const handleSelectFilter = useCallback((filter: ContactFilter) => {
|
||||
setSelectedFilter(filter);
|
||||
@@ -209,6 +214,32 @@ export function ContactsListPage() {
|
||||
|
||||
useEffect(() => {
|
||||
const items = [
|
||||
// New contact — ganz links
|
||||
{
|
||||
id: 'new',
|
||||
plugin: 'contacts',
|
||||
label: t('contacts.create'),
|
||||
type: 'button' as const,
|
||||
group: 'create',
|
||||
icon: <Plus className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
onClick: handleCreate,
|
||||
},
|
||||
// View mode dropdown (list / table / cards)
|
||||
{
|
||||
id: 'view-mode',
|
||||
plugin: 'contacts',
|
||||
label: t('common.view', 'Ansicht'),
|
||||
type: 'dropdown' as const,
|
||||
group: 'view',
|
||||
icon: <LayoutGrid className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
menuWidth: '180px',
|
||||
menuOptions: [
|
||||
{ value: 'list', label: t('contacts.viewList'), icon: <List className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'list', onClick: () => setViewMode('list') },
|
||||
{ value: 'table', label: t('contacts.viewTable'), icon: <Table2 className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'table', onClick: () => setViewMode('table') },
|
||||
{ value: 'cards', label: t('contacts.viewCards'), icon: <LayoutGrid className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'cards', onClick: () => setViewMode('cards') },
|
||||
],
|
||||
onClick: () => {},
|
||||
},
|
||||
// Search
|
||||
{
|
||||
id: 'search',
|
||||
@@ -252,20 +283,20 @@ export function ContactsListPage() {
|
||||
),
|
||||
onClick: () => {},
|
||||
},
|
||||
// View mode dropdown (list / table / cards)
|
||||
// GroupPanel — SmartSuite-style multi-field grouping
|
||||
{
|
||||
id: 'view-mode',
|
||||
id: 'group-panel',
|
||||
plugin: 'contacts',
|
||||
label: t('common.view', 'Ansicht'),
|
||||
type: 'dropdown' as const,
|
||||
group: 'view',
|
||||
icon: <LayoutGrid className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
menuWidth: '180px',
|
||||
menuOptions: [
|
||||
{ value: 'list', label: t('contacts.viewList'), icon: <List className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'list', onClick: () => setViewMode('list') },
|
||||
{ value: 'table', label: t('contacts.viewTable'), icon: <Table2 className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'table', onClick: () => setViewMode('table') },
|
||||
{ value: 'cards', label: t('contacts.viewCards'), icon: <LayoutGrid className="w-3.5 h-3.5" strokeWidth={2} />, active: viewMode === 'cards', onClick: () => setViewMode('cards') },
|
||||
],
|
||||
label: 'Gruppierung',
|
||||
type: 'custom' as const,
|
||||
group: 'group',
|
||||
customComponent: (
|
||||
<GroupPanel
|
||||
groupState={groupState}
|
||||
onGroupChange={setGroupState}
|
||||
contactType={contactType}
|
||||
/>
|
||||
),
|
||||
onClick: () => {},
|
||||
},
|
||||
// Saved filters
|
||||
@@ -278,16 +309,6 @@ export function ContactsListPage() {
|
||||
icon: <Bookmark className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
onClick: () => setSavedFiltersOpen(true),
|
||||
},
|
||||
// New contact
|
||||
{
|
||||
id: 'new',
|
||||
plugin: 'contacts',
|
||||
label: t('contacts.create'),
|
||||
type: 'button' as const,
|
||||
group: 'actions',
|
||||
icon: <Plus className="w-3.5 h-3.5" strokeWidth={2} />,
|
||||
onClick: handleCreate,
|
||||
},
|
||||
// Print
|
||||
{
|
||||
id: 'print',
|
||||
@@ -311,7 +332,7 @@ export function ContactsListPage() {
|
||||
];
|
||||
registerItems('contacts', items);
|
||||
return () => unregisterPlugin('contacts');
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState]);
|
||||
}, [handleSearch, handleCreate, handleSelectFilter, t, registerItems, unregisterPlugin, selectedFilter, viewMode, sortOptions, viewModeOptions, filterState, contactType, sortState, groupState]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full" data-testid="contacts-list-page">
|
||||
|
||||
Reference in New Issue
Block a user