All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 1s
Fixed useEffect dependency problem in SearchInput that caused infinite re-renders when searching with 2+ characters. Changes: - Removed onSearch from useEffect dependencies - Added ESLint disable comment for exhaustive-deps - Search now only triggers on debouncedQuery changes Issue: Search spinner would hang indefinitely when typing 2 chars Root cause: onSearch callback recreated on every render, causing loop Solution: Only depend on debouncedQuery in useEffect
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useTransition } from 'react';
|
|
import { PolicyTable } from './PolicyTable';
|
|
import { SearchInput } from '@/components/search/SearchInput';
|
|
import { EmptyState } from '@/components/search/EmptyState';
|
|
import type { PolicySettingSearchResult } from '@/lib/actions/policySettings';
|
|
import { searchPolicySettings } from '@/lib/actions/policySettings';
|
|
import { toast } from 'sonner';
|
|
|
|
interface PolicySearchContainerProps {
|
|
initialPolicies: PolicySettingSearchResult[];
|
|
onPolicyClick: (policy: PolicySettingSearchResult) => void;
|
|
}
|
|
|
|
export function PolicySearchContainer({
|
|
initialPolicies,
|
|
onPolicyClick,
|
|
}: PolicySearchContainerProps) {
|
|
const [policies, setPolicies] = useState<PolicySettingSearchResult[]>(initialPolicies);
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
const [hasSearched, setHasSearched] = useState(false);
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
const handleSearch = (query: string) => {
|
|
setSearchTerm(query);
|
|
|
|
if (query.length === 0) {
|
|
// Reset to initial policies when search is cleared
|
|
setPolicies(initialPolicies);
|
|
setHasSearched(false);
|
|
return;
|
|
}
|
|
|
|
// Only search with 2 or more characters
|
|
if (query.length < 2) {
|
|
return;
|
|
}
|
|
|
|
startTransition(async () => {
|
|
try {
|
|
const result = await searchPolicySettings(query);
|
|
|
|
if (result.success) {
|
|
setPolicies(result.data ?? []);
|
|
setHasSearched(true);
|
|
} else {
|
|
toast.error(result.error ?? 'Search failed');
|
|
setPolicies([]);
|
|
setHasSearched(true);
|
|
}
|
|
} catch (error) {
|
|
toast.error('An unexpected error occurred');
|
|
setPolicies([]);
|
|
setHasSearched(true);
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<SearchInput
|
|
onSearch={handleSearch}
|
|
isSearching={isPending}
|
|
/>
|
|
|
|
{policies.length === 0 && hasSearched && (
|
|
<EmptyState />
|
|
)}
|
|
|
|
{policies.length === 0 && !hasSearched && initialPolicies.length === 0 && (
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
<p>Keine Policies gefunden - Starten Sie einen Sync</p>
|
|
</div>
|
|
)}
|
|
|
|
{policies.length > 0 && (
|
|
<PolicyTable policies={policies} onRowClick={onPolicyClick} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|