import type { ReactNode } from 'react' /** * Get formatted cell value for display * Handles primitives, arrays, objects, and custom formatters * * @param cellValue - Raw cell value * @param formatter - Optional formatter function * @returns Formatted value for display */ export function getCellValue(cellValue: T): ReactNode { // Handle null/undefined if (cellValue === null || cellValue === undefined) { return '' } // Handle arrays - format as [item1, item2, ...] if (Array.isArray(cellValue)) { const formatted = cellValue .map((item) => (typeof item === 'string' ? `"${item}"` : String(item))) .join(', ') return `[${formatted}]` } // Handle objects - stringify to JSON if (typeof cellValue === 'object') { return JSON.stringify(cellValue) } // Return primitives as-is (string, number, boolean) return cellValue as ReactNode } /** * Compare two values for sorting * Handles strings, numbers, and other types * * @param a - First value * @param b - Second value * @param direction - Sort direction * @returns Comparison result (-1, 0, 1) */ export function compareValues( a: unknown, b: unknown, direction: 'asc' | 'desc', ): number { // Handle null/undefined - always sort to end if (a === null || a === undefined) return 1 if (b === null || b === undefined) return -1 let comparison = 0 if (typeof a === 'string' && typeof b === 'string') { comparison = a.localeCompare(b) } else if (typeof a === 'number' && typeof b === 'number') { comparison = a - b } else if (typeof a === 'boolean' && typeof b === 'boolean') { comparison = a === b ? 0 : a ? 1 : -1 } else if (typeof a === 'object' || typeof b === 'object') { // Compare objects/arrays as JSON strings const strA = JSON.stringify(a) const strB = JSON.stringify(b) comparison = strA.localeCompare(strB) } else { // Fallback for other primitives (bigint, symbol, etc.) comparison = 0 } return direction === 'asc' ? comparison : -comparison } /** * Sort data array by column * * @param data - Data array to sort * @param columnId - Column ID to sort by * @param direction - Sort direction * @returns Sorted data array (new array, does not mutate original) */ export function sortData>( data: T[], columnId: string, direction: 'asc' | 'desc', ): T[] { return [...data].sort((a, b) => compareValues(a[columnId], b[columnId], direction), ) } /** * Paginate data array * * @param data - Data array to paginate * @param page - Current page (0-indexed) * @param rowsPerPage - Number of rows per page * @returns Paginated data slice */ export function paginateData( data: T[], page: number, rowsPerPage: number, ): T[] { const start = page * rowsPerPage const end = start + rowsPerPage return data.slice(start, end) }