@spaced-out/ui-design-system
Version:
Sense UI components library
98 lines (87 loc) • 2.66 kB
Flow
// @flow strict
import * as React from 'react';
import get from 'lodash/get';
import sortBy from 'lodash/sortBy';
import type {GenericObject} from './Table';
export type SortDirection = 'asc' | 'desc' | 'original';
export function useSortableEntries<T: GenericObject>(
entries: Array<T>,
idName: $Keys<T>,
{
defaultSortKey = 'id',
defaultSortDirection = 'original',
onSort,
enableInternalSorting = true,
}: {
defaultSortKey?: $Keys<T>,
defaultSortDirection?: SortDirection,
onSort?: (sortKey: string, sortDirection: SortDirection) => mixed,
enableInternalSorting?: boolean,
},
): {
handleSortClick: (sortKey: $Keys<T>) => mixed,
sortDirection: SortDirection,
sortKey?: string,
sortedEntries: T[],
sortedKeys: $Keys<T>[],
} {
const [sortKey, setSortKey] = React.useState(defaultSortKey);
const [sortDirection, setSortDirection] =
React.useState<SortDirection>(defaultSortDirection);
const getNextDirection = (direction: SortDirection): SortDirection => {
switch (direction) {
case 'original':
return 'desc';
case 'asc':
return 'original';
case 'desc':
return 'asc';
default:
return 'original';
}
};
const advanceSortDirection = (dir: SortDirection) => {
const nextDirection = getNextDirection(dir);
// eslint-disable-next-line unused-imports/no-unused-vars
setSortDirection((dir) => nextDirection);
return nextDirection;
};
const handleSortClick = React.useCallback(
(nextSortKey: string) => {
let nextSortDirection;
if (nextSortKey === sortKey) {
nextSortDirection = advanceSortDirection(sortDirection);
} else {
setSortKey(nextSortKey);
nextSortDirection = 'desc';
}
setSortDirection(nextSortDirection);
onSort?.(nextSortKey, nextSortDirection);
},
[sortKey, sortDirection, entries],
);
const sortedEntries = React.useMemo(() => {
if (!enableInternalSorting || sortDirection === 'original') {
return entries;
}
const caseInsensitiveSortFunction = (entry) => {
if (typeof entry[sortKey] === 'string') {
return entry[sortKey].toLowerCase();
}
return entry[sortKey];
};
const sortedAsc = sortBy(entries, caseInsensitiveSortFunction);
return sortDirection === 'asc' ? sortedAsc : sortedAsc.reverse();
}, [sortDirection, sortKey, entries, enableInternalSorting]);
const sortedKeys = React.useMemo(
() => sortedEntries.map((ent) => get(ent, idName)),
[sortedEntries],
);
return {
sortedEntries,
sortedKeys,
sortDirection,
sortKey,
handleSortClick,
};
}