feat: search test case (#277)
This commit is contained in:
@@ -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}`;
|
||||
|
||||
38
frontend/utils/highlightSearchTerm.tsx
Normal file
38
frontend/utils/highlightSearchTerm.tsx
Normal 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;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
8
frontend/utils/parseQueryParam.ts
Normal file
8
frontend/utils/parseQueryParam.ts
Normal 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))
|
||||
: [];
|
||||
};
|
||||
30
frontend/utils/useDebounce.ts
Normal file
30
frontend/utils/useDebounce.ts
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user