fix(frontend): Prevent full transactions page reload on search.

This commit is contained in:
Elisiário Couto
2025-12-08 16:06:29 +00:00
committed by Elisiário Couto
parent 07edfeaf25
commit 18ee52bdff
2 changed files with 28 additions and 12 deletions

View File

@@ -123,6 +123,7 @@ export default function TransactionsTable() {
search: debouncedSearchTerm || undefined, search: debouncedSearchTerm || undefined,
summaryOnly: false, summaryOnly: false,
}), }),
placeholderData: (previousData) => previousData,
}); });
const transactions = transactionsResponse?.data || []; const transactions = transactionsResponse?.data || [];

View File

@@ -32,22 +32,19 @@ export function FilterBar({
className, className,
}: FilterBarProps) { }: FilterBarProps) {
const searchInputRef = useRef<HTMLInputElement>(null); const searchInputRef = useRef<HTMLInputElement>(null);
const cursorPositionRef = useRef<number | null>(null);
// Maintain focus on search input during re-renders // Maintain focus and cursor position on search input during re-renders
useEffect(() => { useEffect(() => {
const currentInput = searchInputRef.current; const currentInput = searchInputRef.current;
if (!currentInput) return; if (!currentInput) return;
// Only restore focus if the search input had focus before // Restore focus and cursor position after data fetches complete
const wasFocused = document.activeElement === currentInput; if (cursorPositionRef.current !== null && document.activeElement !== currentInput) {
currentInput.focus();
// Use requestAnimationFrame to restore focus after React finishes rendering currentInput.setSelectionRange(cursorPositionRef.current, cursorPositionRef.current);
if (wasFocused && document.activeElement !== currentInput) {
requestAnimationFrame(() => {
currentInput.focus();
});
} }
}, [isSearchLoading]); });
const hasActiveFilters = const hasActiveFilters =
filterState.searchTerm || filterState.searchTerm ||
@@ -83,7 +80,16 @@ export function FilterBar({
ref={searchInputRef} ref={searchInputRef}
placeholder="Search transactions..." placeholder="Search transactions..."
value={filterState.searchTerm} value={filterState.searchTerm}
onChange={(e) => onFilterChange("searchTerm", e.target.value)} onChange={(e) => {
cursorPositionRef.current = e.target.selectionStart;
onFilterChange("searchTerm", e.target.value);
}}
onFocus={() => {
cursorPositionRef.current = searchInputRef.current?.selectionStart ?? null;
}}
onBlur={() => {
cursorPositionRef.current = null;
}}
className="pl-9 pr-8 bg-background" className="pl-9 pr-8 bg-background"
/> />
{isSearchLoading && ( {isSearchLoading && (
@@ -122,7 +128,16 @@ export function FilterBar({
ref={searchInputRef} ref={searchInputRef}
placeholder="Search..." placeholder="Search..."
value={filterState.searchTerm} value={filterState.searchTerm}
onChange={(e) => onFilterChange("searchTerm", e.target.value)} onChange={(e) => {
cursorPositionRef.current = e.target.selectionStart;
onFilterChange("searchTerm", e.target.value);
}}
onFocus={() => {
cursorPositionRef.current = searchInputRef.current?.selectionStart ?? null;
}}
onBlur={() => {
cursorPositionRef.current = null;
}}
className="pl-9 pr-8 bg-background w-full" className="pl-9 pr-8 bg-background w-full"
/> />
{isSearchLoading && ( {isSearchLoading && (