File size: 4,658 Bytes
d97b8f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**

 * Search utility functions for enhanced filtering and searching

 */

/**

 * Performs a fuzzy search on a string, checking if all search terms are present

 * @param searchTerm The search term to look for

 * @param targetString The string to search in

 * @returns true if all search terms are found in the target string

 */
export function fuzzySearch(searchTerm: string, targetString: string): boolean {
  if (!searchTerm.trim()) return true;
  
  const searchWords = searchTerm.toLowerCase().split(/\s+/).filter(word => word.length > 0);
  const target = targetString.toLowerCase();
  
  return searchWords.every(word => target.includes(word));
}

/**

 * Performs a multi-field search across multiple string fields

 * @param searchTerm The search term to look for

 * @param fields Array of strings to search in

 * @returns true if the search term is found in any of the fields

 */
export function multiFieldSearch(searchTerm: string, fields: (string | number)[]): boolean {
  if (!searchTerm.trim()) return true;
  
  const searchLower = searchTerm.toLowerCase();
  
  return fields.some(field => {
    const fieldStr = String(field).toLowerCase();
    return fieldStr.includes(searchLower);
  });
}

/**

 * Highlights search terms in a string by wrapping them with HTML tags

 * @param text The text to highlight

 * @param searchTerm The term to highlight

 * @param className CSS class to apply to highlighted text

 * @returns HTML string with highlighted terms

 */
export function highlightSearchTerm(

  text: string, 

  searchTerm: string, 

  className: string = 'bg-yellow-200'

): string {
  if (!searchTerm.trim()) return text;
  
  const regex = new RegExp(`(${searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
  return text.replace(regex, `<span class="${className}">$1</span>`);
}

/**

 * Debounce function to limit the rate of function calls

 * @param func The function to debounce

 * @param delay The delay in milliseconds

 * @returns Debounced function

 */
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timeoutId: NodeJS.Timeout;
  
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func(...args), delay);
  };
}

/**

 * Creates a search filter function for arrays of objects

 * @param searchTerm The search term

 * @param searchFields Array of field names to search in

 * @returns Filter function that can be used with Array.filter()

 */
export function createSearchFilter<T extends Record<string, any>>(
  searchTerm: string,
  searchFields: (keyof T)[]
) {
  return (item: T): boolean => {
    if (!searchTerm.trim()) return true;
    
    const fieldsToSearch = searchFields.map(field => item[field]);
    return multiFieldSearch(searchTerm, fieldsToSearch);
  };
}

/**

 * Sorts an array of objects by a specific field

 * @param array The array to sort

 * @param field The field to sort by

 * @param direction The sort direction

 * @returns Sorted array

 */
export function sortByField<T extends Record<string, any>>(
  array: T[],
  field: keyof T,
  direction: 'asc' | 'desc' = 'asc'
): T[] {
  return [...array].sort((a, b) => {
    const aValue = a[field];
    const bValue = b[field];
    
    if (typeof aValue === 'string' && typeof bValue === 'string') {
      const comparison = aValue.localeCompare(bValue);
      return direction === 'asc' ? comparison : -comparison;
    }
    
    if (typeof aValue === 'number' && typeof bValue === 'number') {
      const comparison = aValue - bValue;
      return direction === 'asc' ? comparison : -comparison;
    }
    
    if (aValue instanceof Date && bValue instanceof Date) {
      const comparison = aValue.getTime() - bValue.getTime();
      return direction === 'asc' ? comparison : -comparison;
    }
    
    // Fallback to string comparison
    const comparison = String(aValue).localeCompare(String(bValue));
    return direction === 'asc' ? comparison : -comparison;
  });
}

/**

 * Filters an array based on multiple filter criteria

 * @param array The array to filter

 * @param filters Object containing filter criteria

 * @returns Filtered array

 */
export function applyFilters<T extends Record<string, any>>(
  array: T[],
  filters: Record<string, any>
): T[] {
  return array.filter(item => {
    return Object.entries(filters).every(([key, value]) => {
      if (value === 'all' || value === '' || value == null) return true;
      return item[key] === value;
    });
  });
}