feat: search test case (#277)

This commit is contained in:
Eliezer Castro
2025-08-30 11:26:46 -03:00
committed by GitHub
parent afe569a79c
commit f76a3cdaf5
12 changed files with 266 additions and 102 deletions

View File

@@ -26,7 +26,7 @@ async function fetchCase(jwt: string, caseId: number) {
}
}
async function fetchCases(jwt: string, folderId: number, priority?: number[], type?: number[]) {
async function fetchCases(jwt: string, folderId: number, priority?: number[], type?: number[], q?: string) {
const queryParams = [`folderId=${folderId}`];
if (priority && priority.length > 0) {
@@ -37,6 +37,10 @@ async function fetchCases(jwt: string, folderId: number, priority?: number[], ty
queryParams.push(`type=${type.join(',')}`);
}
if (q) {
queryParams.push(`q=${q}`);
}
const query = queryParams.length > 0 ? `?${queryParams.join('&')}` : '';
const url = `${apiServer}/cases${query}`;

View File

@@ -0,0 +1,38 @@
import { cn } from '@heroui/theme';
import { ReactNode } from 'react';
interface HighlightSearchTermProps {
text: string;
searchTerm: string;
className?: string;
minSearchLength?: number;
}
export function highlightSearchTerm({
text,
searchTerm,
className,
minSearchLength = 2,
}: HighlightSearchTermProps): ReactNode {
if (!text || !searchTerm || searchTerm.length < minSearchLength) {
return text || null;
}
const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
const parts = text.split(regex);
return (
<>
{parts.map((part, index) => {
if (regex.test(part)) {
return (
<mark key={`${part}-${index}`} className={cn(className, 'bg-yellow-200 dark:bg-yellow-60 py-0.5 rounded')}>
{part}
</mark>
);
}
return part;
})}
</>
);
}

View File

@@ -0,0 +1,8 @@
export const parseQueryParam = (param: string | null): number[] => {
return param
? param
.split(',')
.map((p) => parseInt(p.trim()))
.filter((p) => !isNaN(p))
: [];
};

View File

@@ -0,0 +1,30 @@
import { useRef, useCallback, useEffect } from 'react';
export default function useDebounce<T extends (...args: any[]) => void>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const debounceFn = useCallback(
(...args: Parameters<T>): void => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
fn(...args);
}, delay);
},
[fn, delay]
);
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return debounceFn;
}