useSortableColumn.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import {useCallback, useMemo} from 'react';
  2. import {GridColumnSortBy} from 'sentry/components/gridEditable';
  3. import {useQuerystringState} from './useQuerystringState';
  4. export function useSortableColumns<T extends string>(options: {
  5. defaultSort: GridColumnSortBy<T>;
  6. querystringKey: string;
  7. sortableColumns: readonly string[];
  8. }) {
  9. const {sortableColumns, querystringKey, defaultSort} = options;
  10. const [queryStringState, _, createLocationDescriptor] = useQuerystringState({
  11. key: querystringKey,
  12. });
  13. const currentSort = useMemo<GridColumnSortBy<T>>(() => {
  14. let key = queryStringState ?? '';
  15. const isDesc = key[0] === '-';
  16. if (isDesc) {
  17. key = key.slice(1);
  18. }
  19. if (!key || !sortableColumns.includes(key as T)) {
  20. return defaultSort;
  21. }
  22. return {
  23. key,
  24. order: isDesc ? 'desc' : 'asc',
  25. } as GridColumnSortBy<T>;
  26. }, [sortableColumns, defaultSort, queryStringState]);
  27. const generateSortLink = useCallback(
  28. (column: T) => {
  29. if (!sortableColumns.includes(column)) {
  30. return () => undefined;
  31. }
  32. if (!currentSort) {
  33. return () => createLocationDescriptor(column);
  34. }
  35. const direction =
  36. currentSort.key === column && currentSort.order === 'desc' ? 'asc' : 'desc';
  37. return () =>
  38. createLocationDescriptor(`${direction === 'desc' ? '-' : ''}${column}`);
  39. },
  40. [currentSort, sortableColumns, createLocationDescriptor]
  41. );
  42. const sortCompareFn = useCallback(
  43. (
  44. a: Partial<Record<T, string | number | any[]>>,
  45. b: Partial<Record<T, string | number | any[]>>
  46. ) => {
  47. const aValue = a[currentSort.key];
  48. const bValue = b[currentSort.key];
  49. if (!aValue || !bValue) {
  50. return 1;
  51. }
  52. if (typeof aValue === 'number' && typeof bValue === 'number') {
  53. if (currentSort.order === 'asc') {
  54. return aValue - bValue;
  55. }
  56. return bValue - aValue;
  57. }
  58. if (typeof aValue === 'string' && typeof bValue === 'string') {
  59. if (currentSort.order === 'asc') {
  60. return aValue.localeCompare(bValue);
  61. }
  62. return bValue.localeCompare(aValue);
  63. }
  64. return 1;
  65. },
  66. [currentSort]
  67. );
  68. return {
  69. currentSort,
  70. generateSortLink,
  71. sortCompareFn,
  72. };
  73. }