Files
syndarix/frontend/src/app/[locale]/(authenticated)/agents/page.tsx
Felipe Cardoso 3cb6c8d13b feat(agents): implement grid/list view toggle and enhance filters
- Added grid and list view modes to AgentTypeList with user preference management.
- Enhanced filtering with category selection alongside existing search and status filters.
- Updated AgentTypeDetail with category badges and improved layout.
- Added unit tests for grid/list views and category filtering in AgentTypeList.
- Introduced `@radix-ui/react-toggle-group` for view mode toggle in AgentTypeList.
2026-01-06 18:17:46 +01:00

117 lines
3.4 KiB
TypeScript

/**
* Agent Types List Page
*
* Displays a list of agent types with search, status, and category filters.
* Supports grid and list view modes with user preference persistence.
*/
'use client';
import { useState, useCallback, useMemo } from 'react';
import { useRouter } from '@/lib/i18n/routing';
import { toast } from 'sonner';
import { AgentTypeList, type ViewMode } from '@/components/agents';
import { useAgentTypes } from '@/lib/api/hooks/useAgentTypes';
import { useDebounce } from '@/lib/hooks/useDebounce';
import type { AgentTypeCategory } from '@/lib/api/types/agentTypes';
export default function AgentTypesPage() {
const router = useRouter();
// Filter state
const [searchQuery, setSearchQuery] = useState('');
const [statusFilter, setStatusFilter] = useState('all');
const [categoryFilter, setCategoryFilter] = useState('all');
const [viewMode, setViewMode] = useState<ViewMode>('grid');
// Debounce search for API calls
const debouncedSearch = useDebounce(searchQuery, 300);
// Determine is_active filter value
const isActiveFilter = useMemo(() => {
if (statusFilter === 'active') return true;
if (statusFilter === 'inactive') return false;
return undefined; // 'all' returns undefined to not filter
}, [statusFilter]);
// Determine category filter value
const categoryFilterValue = useMemo(() => {
if (categoryFilter === 'all') return undefined;
return categoryFilter as AgentTypeCategory;
}, [categoryFilter]);
// Fetch agent types
const { data, isLoading, error } = useAgentTypes({
search: debouncedSearch || undefined,
is_active: isActiveFilter,
category: categoryFilterValue,
page: 1,
limit: 50,
});
// Get filtered agent types
const filteredAgentTypes = useMemo(() => {
if (!data?.data) return [];
return data.data;
}, [data?.data]);
// Handle navigation to agent type detail
const handleSelect = useCallback(
(id: string) => {
router.push(`/agents/${id}`);
},
[router]
);
// Handle navigation to create page
const handleCreate = useCallback(() => {
router.push('/agents/new');
}, [router]);
// Handle search change
const handleSearchChange = useCallback((query: string) => {
setSearchQuery(query);
}, []);
// Handle status filter change
const handleStatusFilterChange = useCallback((status: string) => {
setStatusFilter(status);
}, []);
// Handle category filter change
const handleCategoryFilterChange = useCallback((category: string) => {
setCategoryFilter(category);
}, []);
// Handle view mode change
const handleViewModeChange = useCallback((mode: ViewMode) => {
setViewMode(mode);
}, []);
// Show error toast if fetch fails
if (error) {
toast.error('Failed to load agent types', {
description: 'Please try again later',
});
}
return (
<div className="container mx-auto px-4 py-6">
<AgentTypeList
agentTypes={filteredAgentTypes}
isLoading={isLoading}
searchQuery={searchQuery}
onSearchChange={handleSearchChange}
statusFilter={statusFilter}
onStatusFilterChange={handleStatusFilterChange}
categoryFilter={categoryFilter}
onCategoryFilterChange={handleCategoryFilterChange}
viewMode={viewMode}
onViewModeChange={handleViewModeChange}
onSelect={handleSelect}
onCreate={handleCreate}
/>
</div>
);
}